Skip to content

feat(objects): jev-cron — Jev-gated timer/message triggers - #107

Merged
jmlago merged 2 commits into
mainfrom
feat/jev-cron
Oct 5, 2026
Merged

jmlago merged 2 commits into
mainfrom
feat/jev-cron

Conversation

@jmlago

@jmlago jmlago commented Oct 5, 2026 •

Copy link
Copy Markdown
Member

What

Genswarms.Objects.JevCron is a built-in object. Every every and/or on each message it receives, it asks a Jev decision model (the router's /v1/decisions) to pick one action from a closed catalogue, then applies that action deterministically:

  • produce: send templated messages to agents/objects (subject to topology)
  • change: update its memory with remember/forget; the memory is part of the state Jev sees on the next decision

Jev never writes text. The point is a cheap gate (~$0.00002, under 1 s per decision) in front of expensive LLM agents.

%{name: :watch, handler: Genswarms.Objects.JevCron, config: %{
  every: "10m",
  instructions: "Should the coder act now?",
  actions: [
    %{id: "nothing", when: "Routine or already handled"},
    %{id: "wake", when: "Something is broken and needs a fix",
      send: %{to: :coder, text: "Please fix: {{message}}"},
      remember: %{"last_issue" => "{{message}}"}}
  ],
  min_confidence: 0.6, fallback: "nothing", budget_usd_per_day: 0.10
}}

Details

  • min_confidence + fallback; daily budget; only one decision in flight at a time. Messages that arrive meanwhile wait in a queue (the oldest is dropped beyond 20), and a timer tick that fires during a decision is skipped.
  • Endpoint and key: the endpoint comes from GENSWARMS_JEV_ENDPOINT and the key only from GENSWARMS_JEV_API_KEY, never from the config. A per-object endpoint must pass the EndpointPolicy allowlist; otherwise the object fails to start.
  • Transport is curl (argv, key in a 0700 temp file). :httpc breaks on Erlang builds without http_util, which is the same problem noted in api_client.ex.
  • Every decision is logged as a jev_decision event with the distribution, the top and applied action, the model, the latency and the cost.
  • Its swarm-object.json marks every key except endpoint as x-mutable, so a running jev-cron can be retuned with PATCH /objects/:obj/config.
  • New optional ObjectHandler.validate_config/1, called by SwarmConfig, so config validate rejects a bad object config before start.
  • Docs: a new section in docs/objects.md, plus examples/jev-cron, env vars in getting-started, and CLAUDE.md.

Testing

  • test/genswarms/objects/jev_cron_test.exs (16 tests): validation, endpoint policy, the request/response contract, fallback, errors, queue and coalescing, budget, a policy_ir passthrough, an IR round trip, and an end-to-end run in a real swarm (ObjectServer + Router) against a fake transport.
  • Full mix test: 801 tests, all passing. 14 pre-existing tests need jq, which is not installed on the dev box, so I ran them with nix shell nixpkgs#jq.
  • Live against router.ygr.ai with a jev-1.13 policy: a "backup OK" report gave nothing (1.0) and a "CI red" report gave wake (1.0), ~$0.00002 each.

Not in this PR

  • Cron expressions (only intervals).
  • Persisting memory across object restarts.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added a configurable decision-driven watcher that runs on a schedule or when it receives a message, then takes actions such as sending a report or updating memory.
    • Added an example swarm demonstrating the watcher and its on-call workflow.
    • Added configuration checks that can flag invalid object settings before a swarm starts.
  • Documentation
    • Documented the watcher’s setup, behavior, and required endpoint and API key settings.

jmlago and others added 2 commits October 5, 2026 16:34
Genswarms.Objects.JevCron is a built-in object that, every `every` and/or on
every message it receives, asks a Jev decision model (router /v1/decisions)
to pick one action from a closed catalogue, then applies it
deterministically: templated sends and/or memory changes (remember/forget)
that feed the next decision. Jev never writes text.

- min_confidence + fallback, daily budget, bounded queue, timer coalescing
- endpoint from GENSWARMS_JEV_ENDPOINT; key from GENSWARMS_JEV_API_KEY only,
  per-object endpoints gated by the EndpointPolicy allowlist (fail closed)
- curl transport (argv, key in a 0700 temp file): :httpc is unusable on
  Erlang builds without http_util
- every decision is a jev_decision event (distribution, model, latency, cost)
- swarm-object.json makes everything but endpoint x-mutable via PATCH config
- new optional ObjectHandler.validate_config/1, called by SwarmConfig so
  `config validate` rejects bad object configs before start
- docs/objects.md section, examples/jev-cron, tests incl. a real-swarm run
  and an IR round trip

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 5, 2026

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 64e00712-3e96-4e69-9cc3-dcfd3c27b95d
📥 Commits

Reviewing files that changed from the base of the PR and between 918cb8b and 16d710f.

📒 Files selected for processing (13)
  • CLAUDE.md
  • docs/getting-started.md
  • docs/objects.md
  • docs/testing.md
  • examples/jev-cron/README.md
  • examples/jev-cron/jev_cron_swarm.exs
  • examples/jev-cron/skills/coder.md
  • lib/genswarms/config/swarm_config.ex
  • lib/genswarms/objects/jev_cron/http.ex
  • lib/genswarms/objects/jev_cron/jev_cron.ex
  • lib/genswarms/objects/jev_cron/swarm-object.json
  • lib/genswarms/objects/object_handler.ex
  • test/genswarms/objects/jev_cron_test.exs
 ____________________________________
< LLM (Looking for Leaks in Memory). >
 ------------------------------------
  \
   \   \
        \ /\
        ( )
      .( o ).
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@jmlago
jmlago merged commit 383b353 into main Oct 5, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant