예약 작업(Cron)
자연어 또는 cron 표현식으로 자동 실행될 작업을 예약합니다. Hermes는 schedule/list/remove 도구를 따로 두지 않고, action 방식의 단일 cronjob 도구를 통해 cron 관리를 노출합니다.
현재 cron으로 할 수 있는 일
Cron job으로 할 수 있는 일:
- 한 번만 실행되는 작업 또는 반복 작업 예약
- job 일시 중지, 재개, 수정, 즉시 실행, 삭제
- job에 skill을 0개, 1개 또는 여러 개 연결
- 결과를 원래 채팅, 로컬 파일 또는 설정된 platform 대상으로 전달
- 일반적인 정적 tool 목록을 가진 새 agent session에서 실행
- no-agent mode로 실행 - 일정에 따라 script만 실행하고, stdout을 그대로 전달하며, LLM은 전혀 개입하지 않음. 아래 no-agent mode 섹션을 참고하세요.
이 모든 기능은 Hermes 자체가 cronjob 도구로 사용할 수 있습니다. 따라서 CLI 없이도 일반 문장으로 요청해 job을 만들고, 일시 중지하고, 수정하고, 삭제할 수 있습니다.
Cron으로 실행되는 session 안에서는 다시 cron job을 만들 수 없습니다. Hermes는 무한 예약 루프를 막기 위해 cron 실행 중에는 cron 관리 도구를 비활성화합니다.
예약 작업 만들기
/cron으로 채팅에서 만들기
/cron add 30m "Remind me to check the build"
/cron add "every 2h" "Check server status"
/cron add "every 1h" "Summarize new feed items" --skill blogwatcher
/cron add "every 1h" "Use both skills and combine the result" --skill blogwatcher --skill maps
standalone CLI에서 만들기
hermes cron create "every 2h" "Check server status"
hermes cron create "every 1h" "Summarize new feed items" --skill blogwatcher
hermes cron create "every 1h" "Use both skills and combine the result" \
--skill blogwatcher \
--skill maps \
--name "Skill combo"
자연스러운 대화로 만들기
Hermes에게 평소처럼 요청할 수도 있습니다.
Every morning at 9am, check Hacker News for AI news and send me a summary on Telegram.
Hermes는 내부적으로 통합 cronjob 도구를 사용합니다.
skill 기반 cron job
Cron job은 prompt를 실행하기 전에 하나 이상의 skill을 로드할 수 있습니다.
단일 skill
cronjob(
action="create",
skill="blogwatcher",
prompt="Check the configured feeds and summarize anything new.",
schedule="0 9 * * *",
name="Morning feeds",
)
여러 skill
Skill은 지정한 순서대로 로드됩니다. prompt는 그 skill 위에 얹히는 작업 지시가 됩니다.
cronjob(
action="create",
skills=["blogwatcher", "maps"],
prompt="Look for new local events and interesting nearby places, then combine them into one short brief.",
schedule="every 6h",
name="Local brief",
)
cron prompt 자체에 skill 전문을 길게 넣지 않고, 예약 agent가 재사용 가능한 workflow를 이어받게 만들고 싶을 때 유용합니다.
프로젝트 디렉터리 안에서 job 실행하기
기본적으로 cron job은 특정 repo와 분리되어 실행됩니다. 즉 AGENTS.md, CLAUDE.md, .cursorrules를 로드하지 않으며, terminal/file/code-exec 도구는 gateway가 시작된 작업 디렉터리를 기준으로 실행됩니다. 이를 바꾸려면 CLI에서는 --workdir, tool call에서는 workdir=을 전달합니다.
# Standalone CLI (schedule and prompt are positional)
hermes cron create "every 1d at 09:00" \
"Audit open PRs, summarize CI health, and post to #eng" \
--workdir /home/me/projects/acme
# From a chat, via the cronjob tool
cronjob(
action="create",
schedule="every 1d at 09:00",
workdir="/home/me/projects/acme",
prompt="Audit open PRs, summarize CI health, and post to #eng",
)
workdir가 설정된 경우:
- 해당 디렉터리의
AGENTS.md,CLAUDE.md,.cursorrules가 system prompt에 주입됩니다. 탐색 순서는 interactive CLI와 같습니다. terminal,read_file,write_file,patch,search_files,execute_code는 모두 그 디렉터리를 작업 디렉터리로 사용합니다. 내부적으로는TERMINAL_CWD를 통해 처리됩니다.- 경로는 실제로 존재하는 절대 디렉터리여야 합니다. 상대 경로나 존재하지 않는 디렉터리는 create/update 시점에 거부됩니다.
- 수정할 때
--workdir ""또는 tool call의workdir=""을 전달하면 workdir 설정을 지우고 이전 동작으로 되돌릴 수 있습니다.
workdir가 있는 job은 scheduler tick에서 병렬 pool이 아니라 순차적으로 실행됩니다. 이는 의도된 동작입니다. TERMINAL_CWD가 process-global이므로, workdir job 두 개가 동시에 실행되면 서로의 cwd가 꼬일 수 있습니다. workdir이 없는 job은 이전처럼 병렬 실행됩니다.
job 수정하기
job을 조금 바꾸기 위해 삭제하고 다시 만들 필요는 없습니다.
Chat
/cron edit <job_id> --schedule "every 4h"
/cron edit <job_id> --prompt "Use the revised task"
/cron edit <job_id> --skill blogwatcher --skill maps
/cron edit <job_id> --remove-skill blogwatcher
/cron edit <job_id> --clear-skills
Standalone CLI
hermes cron edit <job_id> --schedule "every 4h"
hermes cron edit <job_id> --prompt "Use the revised task"
hermes cron edit <job_id> --skill blogwatcher --skill maps
hermes cron edit <job_id> --add-skill maps
hermes cron edit <job_id> --remove-skill blogwatcher
hermes cron edit <job_id> --clear-skills
참고:
- 반복된
--skill은 job에 연결된 skill 목록을 새 목록으로 교체합니다. --add-skill은 기존 목록을 교체하지 않고 뒤에 추가합니다.--remove-skill은 특정 연결 skill을 제거합니다.--clear-skills는 연결된 모든 skill을 제거합니다.
lifecycle action
이제 cron job은 create/remove보다 더 넓은 lifecycle을 갖습니다.
Chat
/cron list
/cron pause <job_id>
/cron resume <job_id>
/cron run <job_id>
/cron remove <job_id>
Standalone CLI
hermes cron list
hermes cron pause <job_id>
hermes cron resume <job_id>
hermes cron run <job_id>
hermes cron remove <job_id>
hermes cron status
hermes cron tick
각 action의 의미:
pause- job은 유지하되 더 이상 예약 실행하지 않습니다.resume- job을 다시 활성화하고 다음 미래 실행 시각을 계산합니다.run- 다음 scheduler tick에서 job을 실행하도록 트리거합니다.remove- job을 완전히 삭제합니다.
동작 방식
Cron 실행은 gateway daemon이 처리합니다. gateway는 60초마다 scheduler를 tick하며, 실행 시각이 된 job을 격리된 agent session에서 실행합니다.
hermes gateway install # Install as a user service
sudo hermes gateway install --system # Linux: boot-time system service for servers
hermes gateway # Or run in foreground
hermes cron list
hermes cron status
Gateway scheduler 동작
각 tick에서 Hermes는 다음을 수행합니다.
~/.hermes/cron/jobs.json에서 job을 로드합니다.- 현재 시각과
next_run_at을 비교합니다. - 실행 시각이 된 각 job마다 새
AIAgentsession을 시작합니다. - 연결된 skill이 있으면 새 session에 하나 이상 주입합니다.
- prompt를 끝까지 실행합니다.
- 최종 응답을 전달합니다.
- 실행 metadata와 다음 예약 시각을 업데이트합니다.
~/.hermes/cron/.tick.lock의 file lock은 scheduler tick이 겹쳐 같은 job batch가 두 번 실행되는 것을 막습니다.
전달 옵션
job을 예약할 때 출력이 어디로 갈지 지정합니다.
| Option | 설명 | 예시 |
|---|---|---|
"origin" | job이 만들어진 곳으로 다시 전달 | messaging platform의 기본값 |
"local" | 로컬 파일에만 저장(~/.hermes/cron/output/) | CLI의 기본값 |
"telegram" | Telegram home channel | TELEGRAM_HOME_CHANNEL 사용 |
"telegram:123456" | ID로 지정한 특정 Telegram chat | 직접 전달 |
"telegram:-100123:17585" | 특정 Telegram topic | chat_id:thread_id 형식 |
"discord" | Discord home channel | DISCORD_HOME_CHANNEL 사용 |
"discord:#engineering" | 특정 Discord channel | channel name 기준 |
"slack" | Slack home channel | |
"whatsapp" | WhatsApp home | |
"signal" | Signal | |
"matrix" | Matrix home room | |
"mattermost" | Mattermost home channel | |
"email" | ||
"sms" | Twilio를 통한 SMS | |
"homeassistant" | Home Assistant | |
"dingtalk" | DingTalk | |
"feishu" | Feishu/Lark | |
"wecom" | WeCom | |
"weixin" | Weixin(WeChat) | |
"bluebubbles" | BlueBubbles(iMessage) | |
"qqbot" | QQ Bot(Tencent QQ) | |
"all" | 연결된 모든 home channel로 fan out | 실행 시점에 해석 |
"telegram,discord" | 특정 channel 집합으로 fan out | 쉼표로 구분한 목록 |
"origin,all" | origin과 다른 모든 연결 channel로 전달 | token 조합 가능 |
agent의 최종 응답은 자동으로 전달됩니다. cron prompt 안에서 send_message를 호출할 필요가 없습니다.
routing intent: all
all을 사용하면 설정된 모든 messaging channel에 하나의 cron job을 전달할 수 있습니다. channel 이름을 일일이 나열할 필요가 없습니다. all은 실행 시점에 해석되므로, Telegram을 연결하기 전에 만든 job도 이후 TELEGRAM_HOME_CHANNEL을 설정하면 다음 tick부터 Telegram으로 전달됩니다.
의미상 all은 home channel이 설정된 모든 platform으로 확장됩니다. 대상이 0개여도 괜찮습니다. 이 경우 job은 전달 대상 없이 실행되고, upstream에는 delivery failure로 기록됩니다.
all은 명시 대상과 조합할 수 있습니다. origin,all은 origin chat과 다른 모든 연결 home channel에 전달하며, (platform, chat_id, thread_id) 기준으로 중복을 제거합니다.
응답 wrapper
기본적으로 전달되는 cron 출력에는 예약 작업에서 온 메시지임을 알 수 있도록 header와 footer가 붙습니다.
Cronjob Response: Morning feeds
-------------
<agent output here>
Note: The agent cannot see this message, and therefore cannot respond to it.
wrapper 없이 agent 원본 출력만 전달하려면 cron.wrap_response를 false로 설정합니다.
# ~/.hermes/config.yaml
cron:
wrap_response: false
silent suppression
agent의 최종 응답이 [SILENT]로 시작하면 전달이 완전히 억제됩니다. 출력은 감사용으로 로컬(~/.hermes/cron/output/)에 계속 저장되지만, delivery target으로 메시지는 보내지 않습니다.
이는 문제가 있을 때만 보고해야 하는 monitoring job에 유용합니다.
Check if nginx is running. If everything is healthy, respond with only [SILENT].
Otherwise, report the issue.
실패한 job은 [SILENT] marker와 관계없이 항상 전달됩니다. 성공한 run만 조용히 처리할 수 있습니다.
script timeout
script parameter로 연결된 pre-run script의 기본 timeout은 120초입니다. 예를 들어 bot처럼 보이는 timing pattern을 피하기 위해 randomized delay를 넣는 등 script가 더 오래 걸려야 한다면 timeout을 늘릴 수 있습니다.
# ~/.hermes/config.yaml
cron:
script_timeout_seconds: 300 # 5 minutes
또는 HERMES_CRON_SCRIPT_TIMEOUT 환경 변수를 설정합니다. 해석 우선순위는 env var -> config.yaml -> 기본값 120초입니다.
No-agent mode(script-only job)
LLM reasoning이 필요 없는 반복 job, 예를 들어 classic watchdog, disk/memory alert, heartbeat, CI ping에는 생성 시 no_agent=True를 전달합니다. scheduler는 지정된 schedule에 맞춰 script를 실행하고, agent를 건너뛰고 stdout을 그대로 전달합니다.
hermes cron create "every 5m" \
--no-agent \
--script memory-watchdog.sh \
--deliver telegram \
--name "memory-watchdog"
의미:
- script stdout(trimmed)은 메시지로 그대로 전달됩니다.
- stdout이 비어 있으면 silent tick입니다. 아무것도 전달하지 않습니다. 이것이 watchdog pattern입니다. "문제가 있을 때만 말하기"에 해당합니다.
- non-zero exit 또는 timeout이 발생하면 error alert가 전달됩니다. 깨진 watchdog이 조용히 실패하지 못하게 하기 위해서입니다.
- 마지막 줄의
{"wakeAgent": false}는 silent tick입니다. LLM job에서도 사용하는 같은 gate입니다. - token, model, provider fallback이 없습니다. job은 inference layer를 전혀 건드리지 않습니다.
.sh / .bash 파일은 /bin/bash에서 실행됩니다. 그 외 파일은 현재 Python interpreter(sys.executable)로 실행됩니다. script는 반드시 ~/.hermes/scripts/ 안에 있어야 합니다. pre-run script gate와 같은 sandboxing 규칙입니다.
agent가 대신 설정해 주는 방식
cronjob 도구 schema는 no_agent를 Hermes에 직접 노출합니다. 따라서 chat에서 watchdog을 설명하면 agent가 필요한 설정을 연결하게 할 수 있습니다.
Ping me on Telegram if RAM is over 85%, every 5 minutes.
Hermes는 write_file을 통해 check script를 ~/.hermes/scripts/에 쓴 뒤 다음처럼 호출합니다.
cronjob(action="create", schedule="every 5m",
script="memory-watchdog.sh", no_agent=True,
deliver="telegram", name="memory-watchdog")
메시지 내용이 script만으로 완전히 결정되는 경우, 예를 들어 watchdog, threshold alert, heartbeat에서는 Hermes가 no_agent=True를 자동 선택합니다. 같은 도구로 job을 pause/resume/edit/remove할 수도 있으므로, lifecycle 전체가 CLI 없이 chat으로 구동됩니다.
실제 예시는 Script-Only Cron Jobs guide를 참고하세요.
context_from으로 job 연결하기
Cron job은 이전 run의 기억 없이 격리된 session에서 실행됩니다. 하지만 한 job의 출력이 다음 job에 필요한 context인 경우가 있습니다. context_from parameter는 이 연결을 자동으로 만듭니다. Job B의 prompt 앞에는 runtime에 Job A의 최신 출력이 context로 붙습니다.
# Job 1: Collect raw data
cronjob(
action="create",
prompt="Fetch the top 10 AI/ML stories from Hacker News. Save them to ~/.hermes/data/briefs/raw.md in markdown format with title, URL, and score.",
schedule="0 7 * * *",
name="AI News Collector",
)
# Job 2: Triage - receives Job 1's output as context
# Get Job 1's ID from: cronjob(action="list")
cronjob(
action="create",
prompt="Read ~/.hermes/data/briefs/raw.md. Score each story 1-10 for engagement potential and novelty. Output the top 5 to ~/.hermes/data/briefs/ranked.md.",
schedule="30 7 * * *",
context_from="<job1_id>",
name="AI News Triage",
)
# Job 3: Ship - receives Job 2's output as context
cronjob(
action="create",
prompt="Read ~/.hermes/data/briefs/ranked.md. Write 3 tweet drafts (hook + body + hashtags). Deliver to telegram:7976161601.",
schedule="0 8 * * *",
context_from="<job2_id>",
name="AI News Brief",
)
동작 방식:
- Job 2가 실행될 때 Hermes는
~/.hermes/cron/output/{job1_id}/*.md에서 Job 1의 가장 최근 출력을 읽습니다. - 그 출력은 Job 2의 prompt 앞에 자동으로 붙습니다.
- Job 2는 "이 파일을 읽어라"라는 식으로 hardcode할 필요가 없습니다. content를 context로 받습니다.
- chain 길이는 제한되지 않습니다. Job 1 -> Job 2 -> Job 3 -> ...
context_from이 받는 형식:
| Format | 예시 |
|---|---|
| 단일 job ID(string) | context_from="a1b2c3d4" |
| 여러 job ID(list) | context_from=["job_a", "job_b"] |
출력은 목록에 적힌 순서대로 이어 붙습니다.
사용하기 좋은 경우:
- multi-stage pipeline(collect -> filter -> format -> deliver)
- N단계 작업이 N-1단계의 출력에 의존하는 dependent task
- 여러 job의 결과를 모아 하나의 job이 집계하는 fan-out/fan-in pattern
provider recovery
Cron job은 설정된 fallback provider와 credential pool rotation을 그대로 상속합니다. primary API key가 rate limit에 걸리거나 provider가 오류를 반환하면 cron agent는 다음을 수행할 수 있습니다.
config.yaml에fallback_providers또는 legacyfallback_model이 설정되어 있으면 다른 provider로 fallback- 같은 provider의 credential pool에서 다음 credential로 rotation
따라서 높은 빈도로 실행되거나 사용량이 많은 시간대에 실행되는 cron job도 더 견고합니다. rate limit에 걸린 key 하나 때문에 전체 run이 실패하지 않습니다.
schedule 형식
agent의 최종 응답은 자동으로 전달됩니다. 같은 목적지로 보내기 위해 cron prompt에 send_message를 넣을 필요는 없습니다. cron run이 scheduler가 이미 전달할 정확한 대상에 send_message를 호출하면 Hermes는 중복 전송을 건너뛰고, 사용자에게 보여 줄 내용은 final response에 넣으라고 모델에 알립니다. send_message는 추가 대상이나 다른 대상에 보낼 때만 사용하세요.
상대 지연(one-shot)
30m -> Run once in 30 minutes
2h -> Run once in 2 hours
1d -> Run once in 1 day
interval(recurring)
every 30m -> Every 30 minutes
every 2h -> Every 2 hours
every 1d -> Every day
cron 표현식
0 9 * * * -> Daily at 9:00 AM
0 9 * * 1-5 -> Weekdays at 9:00 AM
0 */6 * * * -> Every 6 hours
30 8 1 * * -> First of every month at 8:30 AM
0 0 * * 0 -> Every Sunday at midnight
ISO timestamp
2026-03-15T09:00:00 -> One-time at March 15, 2026 9:00 AM
반복 동작
| schedule type | 기본 repeat | 동작 |
|---|---|---|
one-shot(30m, timestamp) | 1 | 한 번 실행 |
interval(every 2h) | forever | 삭제될 때까지 실행 |
| cron expression | forever | 삭제될 때까지 실행 |
다음처럼 override할 수 있습니다.
cronjob(
action="create",
prompt="...",
schedule="every 2h",
repeat=5,
)
programmatic job 관리
agent-facing API는 하나의 도구입니다.
cronjob(action="create", ...)
cronjob(action="list")
cronjob(action="update", job_id="...")
cronjob(action="pause", job_id="...")
cronjob(action="resume", job_id="...")
cronjob(action="run", job_id="...")
cronjob(action="remove", job_id="...")
update에서 skills=[]를 전달하면 연결된 skill을 모두 제거합니다.
cron job에서 사용할 수 있는 toolset
Cron은 각 job을 chat platform이 붙지 않은 새 agent session에서 실행합니다. 기본적으로 cron agent는 hermes tools에서 cron platform용으로 설정한 toolset을 받습니다. CLI 기본값도 아니고, 가능한 모든 도구도 아닙니다.
hermes tools
# pick the "cron" platform in the curses UI
# toggle toolsets on/off just like you would for Telegram/Discord/etc.
job별로 더 좁게 제어하려면 cronjob.create의 enabled_toolsets 필드를 사용합니다. 기존 job은 cronjob.update로 바꿀 수 있습니다.
cronjob(action="create", name="weekly-news-summary",
schedule="every sunday 9am",
enabled_toolsets=["web", "file"], # just web + file, no terminal/browser/etc.
prompt="Summarize this week's AI news: ...")
job에 enabled_toolsets가 설정되어 있으면 그 값이 우선합니다. 없으면 hermes tools의 cron-platform config가 우선하고, 그것도 없으면 Hermes가 built-in default로 fallback합니다. 비용 제어 측면에서 중요합니다. 작은 "fetch news" job마다 moa, browser, delegation을 실으면 모든 LLM call에서 tool-schema prompt가 불필요하게 커집니다.
agent를 완전히 건너뛰기: wakeAgent
cron job에 pre-check script(script=)가 붙어 있으면, script가 runtime에 Hermes가 agent를 호출할지 결정할 수 있습니다. stdout의 마지막 줄에 다음 형식을 출력하세요.
{"wakeAgent": false}
그러면 cron은 해당 tick에서 agent run을 완전히 건너뜁니다. 자주 실행되는 polling job(예: 1-2분마다 실행)에서 실제 상태가 바뀔 때만 LLM을 깨우고 싶을 때 유용합니다. 그렇지 않으면 내용이 없는 agent turn에도 계속 비용이 발생합니다.
# pre-check script
import json, sys
latest = fetch_latest_issue_count()
prev = read_state("issue_count")
if latest == prev:
print(json.dumps({"wakeAgent": False})) # skip this tick
sys.exit(0)
write_state("issue_count", latest)
print(json.dumps({"wakeAgent": True, "context": {"new_issues": latest - prev}}))
wakeAgent가 생략되면 기본값은 true입니다. 즉 평소처럼 agent를 깨웁니다.
recipe: 저렴한 pre-run gate
wakeAgent gate는 예약 job이 LLM token을 써야 하는지 $0으로 결정하는 방법입니다. 대부분의 사용 사례는 다음 세 가지 pattern으로 충분합니다.
File-change gate - 감시 중인 파일에 마지막 성공 tick 이후 새 content가 있을 때만 실행합니다. scheduler는 각 job의 last_run_at을 기록하므로, 이를 파일의 mtime과 비교합니다.
#!/bin/bash
# ~/.hermes/scripts/feed-changed.sh
FEED="$HOME/data/feed.json"
STATE="$HOME/.hermes/scripts/.feed-changed.last"
test -f "$FEED" || { echo '{"wakeAgent": false}'; exit 0; }
mtime=$(stat -c %Y "$FEED")
last=$(cat "$STATE" 2>/dev/null || echo 0)
if [ "$mtime" -le "$last" ]; then
echo '{"wakeAgent": false}'
else
echo "$mtime" > "$STATE"
echo '{"wakeAgent": true}'
fi
cronjob(action="create", name="process-feed",
schedule="every 30m",
script="feed-changed.sh",
prompt="A new ~/data/feed.json has landed. Summarize what changed.")
External-flag gate - 다른 process가 준비 완료를 알렸을 때만 실행합니다. 예를 들어 deploy hook이 파일을 떨어뜨리거나, CI job이 state store에 값을 설정하는 경우입니다.
#!/bin/bash
# ~/.hermes/scripts/flag-ready.sh
if test -f /tmp/new-data-ready; then
rm -f /tmp/new-data-ready
echo '{"wakeAgent": true}'
else
echo '{"wakeAgent": false}'
fi
cronjob(action="create", name="nightly-analysis",
schedule="0 9 * * *",
script="flag-ready.sh",
prompt="Run the nightly analysis over today's batch.")
SQL-count gate - 자체 database에 처리할 새 row가 있을 때만 실행합니다. script가 context를 통해 count를 agent에 넘겨 줄 수도 있으므로, agent가 다시 query하지 않아도 작업량을 알 수 있습니다.
#!/usr/bin/env python
# ~/.hermes/scripts/new-rows.py
import json, sqlite3
conn = sqlite3.connect("/home/me/data/app.db")
n = conn.execute(
"SELECT COUNT(*) FROM messages WHERE ts > strftime('%s','now','-2 hours')"
).fetchone()[0]
if n < 1:
print(json.dumps({"wakeAgent": False}))
else:
print(json.dumps({"wakeAgent": True, "context": {"new_rows": n}}))
cronjob(action="create", name="summarize-new-msgs",
schedule="every 2h",
script="new-rows.py",
prompt="Summarize the new messages from the last 2 hours.")
이 pattern은 script에서 query할 수 있는 모든 data source에 적용됩니다. Postgres, HTTP API, 자체 state store 등 무엇이든 가능하며, cron subsystem 안에 SQL evaluator를 따로 넣을 필요가 없습니다.
Hermes 자체의 ~/.hermes/state.db는 release 사이에 바뀔 수 있는 internal schema입니다. pre-run gate에서 query하지 마세요. 대신 여러분의 database나 feed를 바라보게 하세요.
Credit: 이 recipe set은 #2654에서 @iankar8이 sql/file/command trigger를 병렬 mechanism으로 추가하는 방안을 탐색한 데서 출발했습니다. script + wakeAgent gate가 이미 세 가지 경우를 $0으로 모두 처리하므로, 최종 결과는 별도 기능이 아니라 문서로 반영되었습니다.
job chaining: context_from
cron job은 context_from에 다른 job의 이름 또는 ID를 나열해, 그 job들의 가장 최근 성공 출력을 소비할 수 있습니다.
cronjob(action="create", name="daily-digest",
schedule="every day 7am",
context_from=["ai-news-fetch", "github-prs-fetch"],
prompt="Write the daily digest using the outputs above.")
참조된 job들의 가장 최근 완료 출력은 이번 run의 prompt 위에 context로 주입됩니다. 각 upstream entry는 유효한 job ID 또는 이름이어야 합니다. cronjob action="list"를 참고하세요. 참고로 chaining은 가장 최근 완료된 출력을 읽을 뿐이며, 같은 tick에서 아직 실행 중인 upstream job을 기다리지 않습니다.
job storage
job은 ~/.hermes/cron/jobs.json에 저장됩니다. job run의 출력은 ~/.hermes/cron/output/{job_id}/{timestamp}.md에 저장됩니다.
job은 model과 provider를 null로 저장할 수 있습니다. 이 필드가 생략되면 Hermes는 실행 시점에 global configuration에서 값을 해석합니다. per-job override가 설정된 경우에만 job record에 나타납니다.
storage는 atomic file write를 사용하므로, 쓰기 중단으로 인해 job file이 부분적으로만 작성된 상태로 남지 않습니다.
self-contained prompt는 여전히 중요합니다
Cron job은 완전히 새 agent session에서 실행됩니다. prompt에는 연결된 skill이 이미 제공하지 않는, agent가 작업을 완료하는 데 필요한 모든 정보가 들어 있어야 합니다.
BAD: "Check on that server issue"
GOOD: "SSH into server 192.168.1.100 as user 'deploy', check if nginx is running with 'systemctl status nginx', and verify https://example.com returns HTTP 200."
보안
예약 작업 prompt는 생성 및 update 시점에 prompt injection과 credential exfiltration pattern을 검사합니다. 보이지 않는 Unicode trick, SSH backdoor 시도, 명백한 secret exfiltration payload가 포함된 prompt는 차단됩니다.