Meu-Agent / cron
AGENTS.md0 starsChanged 10 days agoMITView on GitHub
Applies on top of the root AGENTS.md. Long-form: website/docs/developer-guide/cron-internals.md; user docs website/docs/user-guide/features/cron.md, kanban.md. cron/jobs.py (job store) + cron/scheduler.py (tick loop; scheduler_*.py siblings). Agents schedule via the cronjob tool; users via hermes cron list|add|edit|pause|resume|run|remove or /cron. Schedules: duration ("30m", "2h", "1d"), "every" phrase ("every 2h", "every monday 9am"), 5-field cron ("0 9 * * *"), ISO one-shot ("2026-06-01T09:00:00Z"). Per-job fields: skills, model/provider overrides, script (pre-run data-collection script whose stdout is injected into the prompt; no_agent=True makes the script the whole job;…
- Reads credentials
1 other project uses a version of this.
Adopted by
Most recently taken up by
- NousResearch/hermes-agentword for word, first seen Oct 2, 2026
Other versions1 project uses a version of this.
Word for word · 1
- NousResearch/hermes-agent★ 262k100% same
Edited · 0
None found.
Wrote their own version · 0
None found.
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 31,439 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository57 other files it gives its agents.
- agent/AGENTS.mdAGENTS.md
- AGENTS.mdAGENTS.md
- gateway/AGENTS.mdAGENTS.md
- hermes_cli/AGENTS.mdAGENTS.md
- hermes_platform/AGENTS.mdAGENTS.md
- plugins/AGENTS.mdAGENTS.md
- pm/AGENTS.mdAGENTS.md
- skills/AGENTS.mdAGENTS.md
- tests/AGENTS.mdAGENTS.md
- tools/AGENTS.mdAGENTS.md
- tui_gateway/AGENTS.mdAGENTS.md
- web/AGENTS.mdAGENTS.md
- apple-notesSkill
- apple-remindersSkill
- findmySkill
- imessageSkill
- claude-codeSkill
- codexSkill
- computer-useSkill
- hermes-agentSkill
- architecture-diagramSkill
- ascii-videoSkill
- baoyu-infographicSkill
- claude-designSkill
- humanizerSkill
- local-pngSkill
- manim-videoSkill
- p5jsSkill
- popular-web-designsSkill
- songwriting-and-ai-musicSkill
- sdlc-reviewSkill
- email-inbox-triageSkill
- himalayaSkill
- youtube-contentSkill
- obsidianSkill
- document-to-action-itemsSkill
- google-workspaceSkill
- mapsSkill
- meeting-action-itemsSkill
- microsoft-officeSkill
- pdfSkill
- product-price-monitorSkill
- teams-meeting-pipelineSkill
- weekly-review-planningSkill
- arxivSkill
- competitor-news-monitorSkill
- grounded-citationsSkill
- xurlSkill
- codebase-inspectionSkill
- dogfoodSkill
- githubSkill
- requesting-code-reviewSkill
- simplify-codeSkill
- spikeSkill
- systematic-debuggingSkill
- test-driven-developmentSkill
- blocked-page-recoverySkill
The file
We split this AGENTS.md into the rules it gives an agent
1 rule. About 0 are common, 0 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 38
Every recurring occurrence is accounted for: tick() advances next_run_at BEFORE dispatch (at-most-once across a mid-run crash) and stamps …
≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
cron/ (+ kanban) — scheduled jobs and the multi-agent work queue
Applies on top of the root AGENTS.md. Long-form: website/docs/developer-guide/cron-internals.md;
user docs website/docs/user-guide/features/cron.md, kanban.md.
Cron
cron/jobs.py (job store) + cron/scheduler.py (tick loop; scheduler_*.py siblings). Agents
schedule via the cronjob tool; users via hermes cron list|add|edit|pause|resume|run|remove or
/cron. Schedules: duration ("30m", "2h", "1d"), "every" phrase ("every 2h", "every monday
9am"), 5-field cron ("0 9 * * *"), ISO one-shot ("2026-06-01T09:00:00Z"). Per-job fields:
skills, model/provider overrides, script (pre-run data-collection script whose stdout is
injected into the prompt; no_agent=True makes the script the whole job; always a FILE under
HERMES_HOME/scripts/, never a command line — script='echo hi' is refused at creation), context_from (chain job
A's last output into job B's prompt), workdir (run with that directory's AGENTS.md/CLAUDE.md
loaded), timezone (pin the cron expression's wall clock to an IANA zone; absent = the profile's
zone), grace_minutes (override the catch-up window; 0 = never catch up, cron only),
multi-platform delivery.
Hardening invariants — each guards a real failure; don't weaken without answering for it:
- Inactivity watchdog on cron agent sessions (
_cron_inactivity_seconds()): default 600s idle,HERMES_CRON_TIMEOUToverrides,0= unlimited. It is idle time, not wall-clock — a stalled session is hard-interrupted so it cannot monopolise the scheduler, while a long-but-active job is never cut off. Attached scripts (pre-run orno_agent) are bounded separately by the script timeout (_DEFAULT_SCRIPT_TIMEOUT, 3600s). - Catch-up window = half the period, clamped to 120s–2h, or the job's
grace_minuteswhen set (0= never catch up — a real value, never "unset":0 == False); 120s grace for missed one-shots. - A pinned
timezoneowns the whole path, not just the compute.compute_next_runresolves job pin → profile zone, and everynext_run_atwrite site must pass the pin (cron/jobs.pycall sites,quota_hold.plan_hold,unreachable_retry.will_retry,extra_fire.settle); one missed site is a burst re-run or a skipped slot._evaluate_due_jobnormalizes the stored instant into the JOB's zone and skips_repair_timezone_shifted_cronfor pinned jobs — that repair is for jobs that follow the profile zone, and on a pinned job its wall-clock predicate reads a due occurrence as future and re-anchors past it (job silently never fires). Knobs live incron/jobs_time.py;timezone/grace_minutesmust stay injob_definition.JOB_DEFINITION_FIELDSor a profile distribution strips them. - Every recurring occurrence is accounted for:
tick()advancesnext_run_atBEFORE dispatch (at-most-once across a mid-run crash) and stampspending_slotin the same save; a scan that finds the stamp with a dead owner restores the instant ONCE (cron/occurrences.py), the executions ledger'sscheduled_instantblocks a second fire,cron.catch_up_missed: falseskips past-grace misses with a logged reason. Never drop a slot silently (#107485). - Per-home tick lock
<home>/cron/.tick.lockprevents duplicate ticks across processes for that profile's store; never a~/.hermes/...literal. - Headless ticks refuse, never spawn.
hermes cron tick(system crontab / external scheduler) callstick(headless=True);cron/scheduler_gateway_gate.pyskips agent jobs when discovery says no gateway owns the home (last_fire_errorstamped, one warning per tick, due instant untouched) instead of lettingrun_canonical_job → connect_gateway → ensure_gateway_runtimespawn an unmanaged daemon. Same policy as approvals (headless/cron = refuse). The in-process ticker andhermes cron runare not headless. - The ticker binds each served profile's scope for the whole tick, including pre-loop code.
scheduler_provider.py::_start_multiplexis ONE ticker iteratingprofiles_to_serve()sequentially under_profile_cron_scope(home)(home + secret scope + terminal scope) — never N threads (module globals race). Everything a tick touches lives inside that guard: store open, lock path, backoff/failure counters (_note_tick_failure), job env construction, and theon_session_endflush of a finished job. Supervision (scheduler_thread.py:: SupervisedTickerThread; start on gateway boot, stand down for homes another gateway already serves, re-enumerate when a profile dir appears or is tombstoned) is per served home, not per process. Why: a store opened before the scope was entered wrote a secondary profile's run records into the launch profile'sjobs.json. - Cron ownership is not gated on
gateway.multiplex_profiles. That flag gates ADAPTERS; one host gateway process ticks EVERY profile's store either way (run.py::_cron_tick_profile_homes). Gating the tick set on it left every non-launch profile's jobs in a store no ticker visited. - Per-profile process assumptions are the bug class. One process ticks N homes, so anything
keyed on "this process's profile" is wrong: in-flight state (
_running_job_ids,_running_since,_running_futures,_running_worker_pids,_running_fire_owners,_interrupted_job_ids) is keyed by_inflight_key(job_id)=(home key, job id)— two profiles legitimately carry adaily-brief; the parallel pool is keyed by home (cron.max_parallel_jobsis per profile); and the stale-code yield gate asksscheduler_ownership.owns_cron_tick_for(home)/live_gateway_ticking(home)instead of the process-global runtime-lock boolean. Public accessors (get_running_job_ids,get_running_job_details,get_wedged_job_ids) still report the host-wide union of bare job ids for the shutdown drain, but LIVENESS consumers (jobs.py::_job_running_in_this_process,tools/cronjob_tools) askis_job_running(job_id, home=...)— the union made profile A's runningdaily-briefanswer for profile B's idle one. - A claim is released under the key it was registered with. The cron scope is a ContextVar:
try_register_running_jobruns on the ticker thread inside_profile_cron_scope, while the pool worker'sfinallysits OUTSIDEctx.runand resolves the LAUNCH home. Pass the registering home (release_running_job(job_id, home=...)), or every secondary profile's claim leaks — the job skips a fire window until the force-release backstop sweeps it, and the drain sees phantom work. Never rebuild a home from a key half (Path(key[0])):hermes_home_keynormcases, so use_inflight_home_path. - Ticked-home state is reclaimed when a home leaves the set.
register_ticked_homesis republished every cycle and reaps the departed homes' parallel pools; pools used to live untilatexit, so each home ever ticked kept a ThreadPoolExecutor and its worker threads forever. - The host gateway stands down for a profile that runs its OWN gateway.
run.py:: _cron_profile_gate(the same gatehermes_cli/web_server.pypasses) keeps the launch process and a per-profile gateway off one store: the tick lock stops a simultaneous double-run but not the race, and when the launch process wins, delivery goes throughSharedRouteAdapters/ fail-closed instead of that profile's live adapters. The gate compares the liveness PID againstos.getpid()— this process holds the launchgateway.pidAND publishes every served profile inserved_profiles, so a bare liveness answer would stand cron down host-wide. - The restart-safe external worker boots itself.
_launch_external_cron_workerpins the checkout — and, on a PM install, the committed generation'ssite-packages— on the child'sPYTHONPATHand marks it_HERMES_CRON_WORKER_BOOT; the child's package entry (cron/__init__.py→cron/worker_bootstrap.py, ahead of thecron.jobsimport —-m cron.schedulerruns the package first) then runs PM'sactivate_dependencies, which leases the committed generation for the worker's lifetime, runs its.pthfiles and activates it before the first third-party import. A failed activation is fatal: the worker exits before its ownership ack (a reported dispatch failure) rather than run on an unleased generation the collector may delete. The gateway never re-runs the boot —hermes_bootstrapalready did at its own launch (#122222). The worker's__main__importshermes_bootstrap(finish_worker_boot) and runsrun_agent's interrupted-pull recovery before it reads the payload, and only then drops the marker: a source-update relaunch (-I, noPYTHONPATH) or a post-restore re-exec must replay the whole worker, never land after the ack with the payload gone and no dependency boot. - Cron sessions pass
skip_memory=True; memory providers intentionally do not run during cron. - Cron execution has its own session. Eligible continuable deliveries may mirror or seed the
reply-facing conversation: origin, origin-less home fallback, user-written bare-platform home,
or opted-in explicit targets.
allexpansions do not gain home mirror eligibility. Mirrored briefs are labelled user turns appended at a turn boundary, preserving role alternation. - The cron ticker runs in the desktop-spawned backend when
HERMES_DESKTOP=1— that env var means "spawned by the app", not "a GUI is watching" (root: capability is a property of the session). - Background
delegate_taskis process-local; work that must survive restarts is a cron job or aterminal(background=True, notify_on_complete=True)process.
Kanban (multi-agent work queue)
Durable SQLite-backed board letting multiple profiles/workers collaborate. Users: hermes kanban
<verb>; dispatcher-spawned workers use a dedicated kanban_* toolset so their schema footprint is
zero outside a kanban task (footprint ladder rung 3).
- CLI:
hermes_cli/kanban.pyfacade + 14kanban_*.pysiblings (boards,db,db_connect,db_dispatch,db_notify,db_graph(task initialization and decomposition),workspace, ...). Verbs:init, create, list (ls), show, assign, link, unlink, comment, attach, attachments, attach-rm, complete, request-review, request-changes, reopen-review, block, unblock, archive, tail, pluswatch, stats, runs, log, assignees, heartbeat, notify-*, dispatch, daemon, gc. Argparse alias dispatch must accept bothlistandls(root). - Toolset:
tools/kanban_tools.py—kanban_show, kanban_complete, kanban_request_review, kanban_request_changes, kanban_block, kanban_schedule, kanban_heartbeat, kanban_comment, kanban_create, kanban_link, kanban_attach, kanban_attach_url, kanban_attachments; platforms whose saved selection enableskanban(hermes tools enable kanban --platform <p>; default-off, inCONFIGURABLE_TOOLSETS) get the full set pluskanban_list/kanban_unblockfor board routing. The check_fn reads the schema build's own selection (tools/kanban_toolset_context.py), never the legacy top-leveltoolsetskey alone. - Dispatcher: long-lived loop (default 60s) that reclaims stale claims, promotes ready tasks,
atomically claims, and spawns assigned profiles. Runs inside the gateway by default
(
kanban.dispatch_in_gateway: true). Standalone:plugins/kanban/systemd/hermes-kanban-dispatcher.service. - Plugin assets:
plugins/kanban/dashboard/(web UI) + systemd unit.kanban_db.connectis its own connection helper — do not alias it toprojects_db.connect(a path-proximity generator did).
Isolation: board is the hard boundary — workers get HERMES_KANBAN_BOARD pinned in their env and
cannot see other boards; tenant is a soft namespace within a board (workspace-path + memory-key
isolation, one fleet serving several businesses). After kanban.failure_limit consecutive
non-success attempts on a task (default 2) the dispatcher auto-blocks it to stop spin loops; a
worker exit of KANBAN_TERMINAL_PROVIDER_EXIT_CODE (78 — credential revoked, model gone; the
worker's own failure_reason classification via cli._TERMINAL_PROVIDER_REASONS) trips it on
the first attempt, sticky, because no retry can heal it (#114587).
Process-identity note: kanban --preserve-cache contains "serve" — never classify processes by argv
substring (root). Worker liveness is (worker_pid, worker_started_at) — the start-time fingerprint
(gateway.status.get_process_start_time) recorded at claim time — never bare PID existence, or a
recycled PID gets killed on reclaim.
- Notifications leave through the task's owning profile.
hermes_cli/kanban_db_notify.pysubscriptions carry the profile;gateway/kanban_watchers_notifier.pydelivers via THAT profile's adapter under its scope (_notify_profile_filter), never the multiplexer's launch adapter; a fail-closed skip logs once at WARNING with the remedy, never a barecontinue. Dispatched workers getHERMES_KANBAN_BOARDand the assignee'sHERMES_HOMEpinned in a scrubbed child env (build_subprocess_env+strip_launch_profile_env); they never inherit the default profile's.env. - Prompt injection sites gate on ownership, not tool access. Tool access (
kanban_showvisible via a profile's toolset) and an inheritedHERMES_KANBAN_TASK(delegate children, cron runs beside a worker) are not ownership. The kanban guidance (agent_init,system_promptfallback) and the stop nudge resolve the task viaagent/delegation_context.py::owned_kanban_task(); other readers pair their env read withis_dispatcher_owned_worker_context(). - Descendant fence is a path, not a flag. A delegated child's Kanban marker
(
agent/delegation_context.py::DELEGATED_CHILD_ENV_MARKER) carries the fenced board ROOT;kanban_path_is_fenced(path)denies mutations only on the dispatcher-pinnedHERMES_KANBAN_DBor under that root, so a child working against a scratchHERMES_HOMEkeeps a writable board.
Tests
tests/cron/, tests/hermes_cli/test_kanban*.py, tests/tools/test_kanban*.py. Schedule parsing
and catch-up windows are pure functions — test them as data. Never assert on the verb list or
toolset size (root: no change-detectors). Time-based tests use loose bounds (≥ 2s) and event sync.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

