Skip to content

feat(jobs): per-job notification targets (notify_to) #244

Description

@chrisbonilla95

Problem

Scheduled jobs with notify: true all forward to the same place — every user in telegram.allowedUserIds — via forwardToTelegram (src/commands/start.ts). There's no way for the owner to route a specific job's output to a specific chat they control: e.g. sending a noisy or low-priority job to a dedicated private log channel / forum topic you own, while keeping other jobs in your main DM.

Proposed Solution

Add an optional notify_to field to job frontmatter: a list of chat IDs the notification should go to (your DM, or a private channel / forum topic you own). When set, the job's output goes to exactly those chats; when omitted, behaviour is unchanged (falls back to allowedUserIds). Heartbeats and manual triggers are untouched. (notify_to mirrors the existing retry_delay snake_case convention; camelCase notifyTo is also accepted.)

---
schedule: "0 9 * * 1"
notify: true
notify_to: [123456789]   # route this job to a specific chat you own (e.g. a log channel/topic)
---

Proposed Changes

1. src/jobs.ts

Add notifyTo?: number[] to the Job interface and parse it in parseJobFile (tolerant of comma- and/or whitespace-separated ids; malformed input warns and yields undefined rather than changing where output goes):

const notifyToKey = /^notify_?[tT]o:/;
const notifyToLine = lines.find((l) => notifyToKey.test(l));
const notifyToParsed = notifyToLine
  ? parseFrontmatterValue(notifyToLine.replace(notifyToKey, ""))
      .replace(/[[\]]/g, " ").split(/[\s,]+/)
      .map((s) => parseInt(s, 10)).filter((n) => Number.isFinite(n))
  : [];
const notifyTo = notifyToParsed.length > 0 ? notifyToParsed : undefined;

2. src/commands/start.ts

Give forwardToTelegram an optional targets argument (default = current behaviour) and pass the job's notifyTo:

function forwardToTelegram(label, result, targets?: number[]) {
  const recipients = targets && targets.length > 0 ? targets : currentSettings.telegram.allowedUserIds;
  if (!telegramSend || recipients.length === 0) return;
  // ...unchanged...
  for (const userId of recipients) { /* ... */ }
}
// at the job-notify call site:
forwardToTelegram(job.name, r, job.notifyTo);

Open questions

  • Field name: I went with notify_to (consistent with retry_delay); happy to rename.
  • Telegram-first, or add the same to Discord/Slack for parity in one go?

Branch (implemented, with parser tests): https://github.com/chrisbonilla95/claudeclaw/tree/feat/job-notify-targets
(diff vs master: master...chrisbonilla95:claudeclaw:feat/job-notify-targets) — can open a PR if the approach looks good.


Posted by Claude after discussing with @chrisbonilla95

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions