Skip to content

feat: trigger visibility — indicators, discovery, and run history #271

@nathanschram

Description

Summary

The trigger system (crons + webhooks) is currently configured but largely invisible to users in the Telegram UI. Once set up in untether.toml, there's no easy way to discover what triggers exist, which chats they target, when they last fired, or whether a run was trigger-initiated.

This issue tracks improvements to surface trigger presence, activity, and management across the Untether UI.

Current state

Area What exists today Gap
Startup message Global count: "triggers: enabled (N webhooks, M crons)" Not per-chat; doesn't say which chats have triggers
Per-chat indicator Nothing No visual cue that a chat has active triggers
Trigger dispatch ⚡ Trigger: webhook:id / 🕐 Scheduled: cron:id notification Silent (notify=False), no schedule/context info
Run footer Shows model/effort/permission Identical for trigger-initiated and manual runs
/config menu Trigger mode page (all/mentions) No view of configured cron/webhook triggers
/trigger command Sets trigger mode (all/mentions) Doesn't list or describe configured triggers
Run history last_fired dict — in-memory, per-cron, lost on restart No persistent history, no UI display
Cron schedule display Raw 5-field expression stored No human-friendly rendering
Stats Per-engine run counts No trigger vs manual breakdown

Proposed improvements

Tier 1 — Quick wins (v0.35.2)

1a. Per-chat trigger indicator in startup/greeting
When the bot starts (or on /ping), if the current chat has triggers configured, append a line:

⏰ triggers: 1 cron (daily-review, 8am Mon–Fri Melbourne)

Requires a reverse lookup: iterate trigger_settings.crons + .webhooks, match chat_id → current chat. Lightweight, no persistence needed.

1b. Trigger-initiated run footer
When a run was started by a trigger, add to the meta line:

🏷 sonnet · plan · ⏰ cron:daily-review

or

🏷 sonnet · plan · ⚡ webhook:github-push

Pass trigger source through RunOptions or ProgressTracker.meta so format_meta_line() can render it.

1c. Human-friendly cron description
Add a describe_cron(schedule, timezone) utility that converts 0 8 * * 1-5 + Australia/Melbourne"8:00 AM Mon–Fri (Melbourne)". Used in startup indicator, /config page, and dispatch notifications. Keep it simple — cover common patterns, fall back to raw expression for complex ones.

Tier 2 — Discovery (v0.35.2–0.35.3)

2a. /config → Triggers sub-page
Add a triggers info page to the /config menu showing:

  • Active crons: id, schedule (human-friendly), timezone, project, engine
  • Active webhooks: id, path, auth type, project, engine
  • Per-chat filtering: only show triggers targeting this chat (or all if in default chat)

Read-only view — editing stays in untether.toml. This gives users a way to see what's configured without SSH.

2b. Enhanced dispatch notification
Improve the cron/webhook notification messages:

⏰ Scheduled: cron:daily-review
📅 8:00 AM Mon–Fri (Melbourne) · project: myapp

Add schedule context and project info. Still silent (notify=False), but more informative when scrolling history.

Tier 3 — History & stats (v0.35.3+)

3a. Persistent trigger run history
Track last_fired_at (UTC timestamp) per trigger in a JSON state file (similar to chat_prefs pattern). Show in /config triggers page:

⏰ daily-review — 8:00 AM Mon–Fri (Melbourne)
   Last run: today 8:00 AM · next: tomorrow 8:00 AM

3b. Trigger activity in /stats
Add trigger-initiated run counts alongside engine counts:

Runs today: 5 (3 manual, 2 triggered)
  cron:daily-review — 1 run
  webhook:github-push — 1 run

Extend DayBucket in session_stats.py with an optional source field.

3c. Trigger run notifications
Optional: when a trigger fires and completes, send a brief completion notification (configurable). Useful for webhook-triggered runs that complete while the user isn't watching.

Key files

File Relevance
src/untether/telegram/loop.py:143-157 Startup message construction
src/untether/markdown.py:312-394 Footer/meta line formatting
src/untether/triggers/dispatcher.py:30-86 Trigger dispatch notifications
src/untether/triggers/cron.py Cron scheduler + matching
src/untether/triggers/settings.py CronConfig/WebhookConfig models
src/untether/telegram/commands/config.py:924-988 /config trigger mode page
src/untether/telegram/commands/trigger.py /trigger command (mode only)
src/untether/session_stats.py Run stats tracking
src/untether/telegram/chat_prefs.py Per-chat state storage

Design notes

  • No new dependencies — human-friendly cron description is a simple pattern-matching function
  • Read-only UI — trigger config stays in untether.toml; Telegram shows info, doesn't edit
  • Backward compatible — all new UI elements are additive; no existing behaviour changes
  • Per-chat awareness requires iterating trigger configs to find matching chat_id — cheap at startup, could be cached in TransportRuntime

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions