Skip to content

Completion of a long AI agent task

Modern AI-coding flow is “we go get coffee while the agent explores options.” Claude Code, Codex CLI, Cline, Aider, OpenAI Agents SDK, LangGraph-runner — they can all run for minutes or hours. Returning to the terminal every 30 seconds is not an option.

Let’s wrap any such run in a small wrapper that sends a push to Notifly on completion (or on error).

/usr/local/bin/agent-run
#!/usr/bin/env bash
set -u
set -a; source ~/.notifly.env; set +a
CMD="$*"
START=$(date +%s)
HOST=$(hostname -s)
LOG=$(mktemp)
if "$@" 2>&1 | tee "$LOG"; then
RC=0
else
RC=$?
fi
DUR=$(( $(date +%s) - START ))
# try to extract the "final answer" from the last lines to include in the message
TAIL=$(tail -c 1200 "$LOG")
LINES=$(wc -l < "$LOG")
if [[ $RC -eq 0 ]]; then
TITLE="🤖✅ ${CMD:0:60}"
PRIO=5
else
TITLE="🤖❌ ${CMD:0:60} (rc=$RC)"
PRIO=9
fi
curl -fsS "$NOTIFLY_URL/message?token=$NOTIFLY_TOKEN" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg t "$TITLE" --arg m "Длительность: ${DUR}s
Хост: $HOST
Строк лога: $LINES
Конец вывода:
$TAIL" --argjson p $PRIO '{title:$t, message:$m, priority:$p}')" >/dev/null
rm -f "$LOG"
exit $RC

Usage:

Окно терминала
agent-run claude --print "Перепиши auth-service на async и почини тесты"
agent-run aider --yes "fix flaky tests in tests/integration/"
agent-run codex exec "rebase feature branch onto main, resolve conflicts"

If you’re writing a custom agent on LangGraph / Agents SDK / your own loop:

import os, time, traceback, functools, requests
def notify_when_done(name=None, priority_ok=5, priority_fail=9):
def deco(fn):
@functools.wraps(fn)
def wrap(*args, **kwargs):
label = name or fn.__name__
t0 = time.time()
try:
result = fn(*args, **kwargs)
_push(f"🤖✅ {label}",
f"OK за {int(time.time()-t0)}s\n\n{_summary(result)}",
priority_ok)
return result
except Exception:
_push(f"🤖❌ {label}",
f"FAIL за {int(time.time()-t0)}s\n\n{traceback.format_exc()[-1500:]}",
priority_fail)
raise
return wrap
return deco
def _summary(result):
if isinstance(result, dict):
steps = result.get("steps") or result.get("tool_calls") or []
return f"Итераций: {len(steps)}\nИтог: {str(result.get('output',''))[:600]}"
return str(result)[:1000]
def _push(title, msg, prio):
requests.post(f"{os.environ['NOTIFLY_URL']}/message",
params={"token": os.environ["NOTIFLY_TOKEN"]},
json={"title": title, "message": msg, "priority": prio},
timeout=5)
@notify_when_done(name="rag-reindex")
def reindex_all_docs():
...

From successful experience:

  • Duration. Сколько ушло секунд — main signal whether to panic.
  • Cost. If known — ~$2.40 на токенах or the number of tool calls.
  • Diff/files. For coding agents — Изменено файлов: 12, +340 −180.
  • Output tail. 1–2 KB of the final log — usually the result is there.
  • Link. To a PR / commit / dashboard — this works even from push, Notifly supports extras with URL.