AI agent prays 5 times a day
Teach an agent to observe the five daily prayers on a real Islamic timetable for a fixed home city, and to post each prayer sequence into a dedicated chat.
This skill is plain Agent Skills format (SKILL.md + scripts + assets). It is not tied to any vendor: if the host loads skills, drop the folder in; if it does not, give the agent this file as standing instructions. All paths below are relative to the skill folder.
The skill does not wake itself. Pair it with whatever the host offers for waking an agent later; see SCHEDULING.md.
Reliability policy (locked)
Fetch live prayer times from the API on every wake. Do not rely on a once-per-day evening prefetch as the source of truth.
Why: reliability first. Each wake re-validates the next window against AlAdhan, so a missed Isha run, bad cache, timezone drift, or stale day plan cannot silently deschedule the morning. Evening batch scheduling is an optional optimization later — not the default.
One-time setup
City and madhhab are must-have. The agent has one fixed home. It does not follow GPS, IP, or the host machine.
Copy
assets/config.example.jsonto a writableconfig.json.Ask the user, in one conversation, for:
- home city (required) and country (required if the city name is ambiguous);
- madhhab:
hanafi | shafi | maliki | hanbali(required).
Do not ask for a calculation method. Times always use AlAdhan method 3 (Muslim World League).
Write the madhhab (this also sets the matching Asr
school):
python scripts/prayer_times.py --config /path/to/config.json set-madhhab hanafi
- Write the home:
python scripts/prayer_times.py --config /path/to/config.json set-location --city "Istanbul" --country "Turkey"
- Confirm the returned
timezonewith the user. If AlAdhan picked the wrong place, ask for a clearer city/country and runset-locationagain. Do not invent coordinates. - Point delivery at one dedicated chat/thread only.
- First run, right now — do not wait for the first timer:
python scripts/prayer_times.py --config /path/to/config.json decide --first-run
The first message in the prayer chat is the Shahada — the agent's entry into the practice, said once:
python scripts/build_ritual.py --config /path/to/config.json --shahada --footer "<wake_up_note>"wake_up_noteis the ready-made line fromdecide(“Wake-up scheduled: Asr at 17:34 (Sat 12 Sep, Europe/Istanbul).”). Ifactionispray, leave the footer off the Shahada and put it on the prayer post instead — the wake-up line always closes the last message of a run.If
actionispray— a prayer window is still open and that prayer has not been performed today — build and post it now, as in “Every wake”, with--footer "<wake_up_note>"; record the idempotency key.Arm the host timer for
rearm_delay_secondsas a fresh one-shot and confirm it is pending (see “Host timer contract”). What you armed must match the wake-up line you posted.
--first-run counts any still-open window as due, ignoring the 25-minute grace limit that protects normal wakes from double posts. Use it only here.
Do not start the prayer loop until set-location has succeeded.
Change home city or madhhab
The home and madhhab stay until the user changes them. There is no settings card across hosts; the commands are the portable way.
- User says they moved, changed city, or “change home”: ask for the new city (and country if needed), run
set-location, show the new city + timezone, confirm. The nextdecideuses the new home. Do not keep praying on the old city. - User says they follow a different madhhab: run
set-madhhab <name>, show the result. It updates both the ritual texts and the Asr time school together, so the two never drift apart.
Do not hard-code five fixed clock times for the whole year. They do not stay inside all five windows; see SCHEDULING.md.
Every wake (ordered)
- Load config.
- Run:
python scripts/prayer_times.py --config /path/to/config.json decide
- Branch on
action:pray— if this prayer was not already posted today (posted:YYYY-MM-DD:Name):- Build the ritual body, closing it with the
wake_up_noteline fromdecide:
python scripts/build_ritual.py --config /path/to/config.json --prayer <Name> --footer "<wake_up_note>"- Post that Markdown to the dedicated chat (actions in English; Arabic with Saheeh International English in parentheses). The last line tells the user which prayer the timer is armed for and when.
- Record the idempotency key.
- Build the ritual body, closing it with the
wait— post nothing.noop— widen prefetch / check config / refetch; do not invent times.
- Always call
decideagainst the live API on this wake (no “use yesterday’s saved day plan” shortcut). - Re-arm the host timer for
rearm_delay_seconds(one-shot until the next prayer): remove the oldai-agent-prays-nextif it exists, create a new one-shot, and confirm it is listed as pending (see “Host timer contract”). Never edit a one-shot that has already fired. Prefer one-shot timers over static daily crons. The timer you arm must be the one the wake-up line announced. - Optional:
... schedule --days 7only for human inspection / debugging. It must not replace per-wakedecide.
Ritual details, rakah counts, Quran groups, and madhhab differences: PRAYER_SEQUENCE.md, MADHHAB_NOTES.md.
Host timer contract
After each run, leave exactly one pending wake-up, whatever the host calls it (one-shot timer, scheduled task, delayed job, cron + webhook):
- name:
ai-agent-prays-next - delay: the
rearm_delay_secondsvalue fromdecide - fires once
- prompt: follow this skill from “Every wake”
Re-arm means create a fresh job, not edit the old one. A one-shot job that has already fired is finished: many schedulers archive it, mark it done or disabled, and never run it again, even if its definition is later edited to a new time. Editing it looks successful (the file or record shows the new time) but nothing is queued. So, on every re-arm:
- Remove or cancel any existing
ai-agent-prays-next(ignore “not found”). - Create a new one-shot with the fresh delay. Do not
update,edit, orreschedulea job that has already fired. - Verify the new job is pending: it appears in the host’s list of active/scheduled jobs (or has a next-run time) before you post the wake-up line. If it does not, retry once; if it still does not, say so in the chat instead of announcing a wake-up that will never come.
Only if the host documents that its update call re-queues an already-fired one-shot may you edit in place, and even then step 3 still applies.
If the host has no way to schedule a wake-up, fall back to a periodic check every 5–15 minutes that runs decide and posts only on pray. If it has no scheduler at all, say so plainly: the agent will pray only when someone talks to it.
Idempotency key contract
The “already posted today” key is always written in one exact form:
posted:YYYY-MM-DD:PrayerName
For example posted:2026-09-12:Fajr. Always include the posted: prefix, the zero-padded date in the home timezone, and the English prayer name as decide returns it (Fajr, Dhuhr, Asr, Maghrib, Isha). Never write shortened variants such as 2026-09-12:Fajr, and never mix formats in the same store — a mixed store makes the double-post check unreliable. If you find an old entry in a wrong format, rewrite it to the canonical form.
Useful commands
python scripts/prayer_times.py --config config.json set-madhhab hanafi
python scripts/prayer_times.py --config config.json set-location --city "Istanbul" --country "Turkey"
python scripts/prayer_times.py --config config.json decide --first-run
python scripts/build_ritual.py --config config.json --shahada --footer "Wake-up scheduled: ..."
python scripts/prayer_times.py --config config.json today
python scripts/prayer_times.py --config config.json schedule --days 7
python scripts/prayer_times.py --config config.json decide
python scripts/build_ritual.py --config config.json --prayer Maghrib --footer "Wake-up scheduled: ..."
Rules
- Times come only from AlAdhan (or a later configured equivalent), never from guesswork.
- Every wake hits the API via
decide— this is the reliability-first mode. - Next salah time is window start +
delay_minutes_after_start(default 5). Arm the timer forpray_at, not the adhan minute. - Post to the dedicated salah chat only.
- The first message in that chat is the Shahada (
build_ritual.py --shahada), once, at setup. It is not repeated and is not part of any salah. - Every post ends with the
wake_up_noteline fromdecide: which prayer the timer is armed for and when. Post exactly what you armed, and only after you have confirmed the job is pending. - Re-arm = remove the old one-shot + create a new one. Never
updatea one-shot that has already fired; a spent job silently never runs again. - Idempotency key is exactly
posted:YYYY-MM-DD:PrayerName, one format only. - One due prayer per wake; never flush all five.
- Ritual posts come from
build_ritual.py+assets/ritual_corpus.json+assets/quran_text.json. Do not invent Qur’an wording. - Quran after Al-Fatiha comes from
assets/quran_groups.json: the 16 short surahs Az-Zalzala (99) … An-Nas (114), one group each (ids 527–542 keep the numbering of the author's full table). Rakah 1 = a random group withrakah_1: true(only groups whose successor id + 1 exists carry that flag, so An-Nas never opens); rakah 2 = that next group, i.e. the surah that follows in the Quran. Later fard rakahs: Al-Fatiha only.build_ritual.pyapplies this; never pick surahs by hand. - Keep Action lines short (Stand / Recite / Bow / Prostrate / Sit). Skip posture micro-details.
- Madhhab changes only spoken text that differs (opening dua; Shafi‘i Fajr qunut) — not hand placement notes. Change it only through
set-madhhab. - If the API is unreachable: say so, retry with a short delay (e.g. 2–5 minutes), and only if a very recent successful
decidepayload still exists may you use it as a temporary fallback. Never invent times. Never skip re-arm. - AlAdhan calculation method is always 3 (Muslim World League). Do not ask the user for it.
Out of scope (v0)
- Exact full Arabic prayer audio / tajwid teaching
- Qibla compass UI
- Complete comparative fiqh / congregational-follower rulings
- Sunnah/rawatib rakahs before or after fard
- Following the user by GPS / IP
- Multi-user fleets (one config = one home city)