Open beta · free accounts
Run your AI work when power is cheap.
Async Energy shifts your agents, batch inference, fine-tunes, and device charging into the cheapest electricity hours of the day — without ever missing a deadline. Then it measures what each run actually drew, so the savings are a number you can check rather than a claim we make.
$ git clone https://github.com/boringbots/async-energy-controller.git
The premise
Electricity is not one price. Your GPU does not know that.
On a time-of-use or day-ahead tariff the same kilowatt-hour can cost three or four times more at 7pm than at 3am. Every batch job you kick off during the day is paying the peak rate for work that had no reason to happen right then.
Moving that work is easy to say and annoying to do: you would have to know tomorrow's prices, know what each job actually draws, know how long it takes, and still guarantee it finishes before anyone needs it. That is the whole job of this tool.
What people schedule
Anything that has to be done by morning, not done right now.
Agent pipelines
Overnight research runs, report generators, scheduled multi-step automations. Wrap the invocation in a script and the scheduler decides when it fires.
adapter command
Batch inference & embeddings
Nightly RAG index refreshes, classification and enrichment queues, anything that chews through a backlog against a local model server.
adapter ollama · openai
Fine-tunes & eval sweeps
Long jobs where nobody is watching the clock — only the finish time matters. The most energy per job, so the most to save.
adapter command
Robots & devices
Charge the mower, the vacuum, the home robot — and run its on-box compute — in the cheap hours. Anything you can trigger from a shell command is schedulable.
adapter command
Media generation queues
Image, video, and audio batches that need to exist by morning but do not need to exist at 7pm when power costs triple.
adapter openai · command
Anything with a deadline
The rule of thumb: if the work has a due time rather than a start time, it belongs here. If the start time cannot move, there is nothing to optimize.
The loop
Set it up once. Then it is a background process.
- 01
Describe the work
One call per workload: what framework it uses, how often it recurs, the earliest it may start, and when it must be done by.
- 02
Map it on your box
A local jobs.json says what each workload actually executes here. The server never pushes a command — it only ever names one you already wrote down.
- 03
Sleep
Every night the optimizer pulls your location’s real price curve and plans the cheapest feasible slot for every job, respecting every deadline.
- 04
It runs, and reports back
The controller executes each job inside its window under a GPU energy profiler, then reports the measured energy — which sharpens tomorrow’s plan.
curl -X POST https://api.async.energy/api/v1/workflows \
-H "Authorization: Bearer $TOKEN" \
-d '{
"name": "nightly-embeddings",
"framework": "ollama",
"request": {"model": "nomic-embed-text"},
"recurrence": "daily",
"earliest_start": "22:00",
"deadline": "by 7am"
}' {
"wf_a1b2c3": {
"framework": "ollama",
"request": {
"model": "nomic-embed-text",
"prompt_file": "/data/queue/embed-batch.txt"
}
}
}
Rather watch than curl?
Sign in to your dashboard to see tonight's plan on your price curve, a card per workload with what
scheduling saved, and the real power trace of every run.
Why you can point this at your machine
A daemon with a deadline and shell access is a lot to ask for.
So the design gives away as little as possible, and the parts that run on your hardware are the parts you can read.
Your box only runs what you wrote down
The controller resolves a scheduled workflow through your local job catalog. A workflow with no local entry is skipped with a warning. There is no code path where the cloud hands your machine a command to execute.
The controller is open source
It is deliberately small and deliberately dumb — it never optimizes, never decides, and talks to exactly one host. Small enough to read in an afternoon before you give it a systemd unit.
Energy is measured, not estimated
Power draw is sampled at 1 Hz and energy read from the GPU’s hardware counter where it exists. If the box cannot measure it, the field is null — never a plausible-looking number that was actually a guess.
Deadlines are hard constraints
A job that cannot make its deadline is shown to you as infeasible with a reason. It is never quietly dropped and never run late to save a few cents.
It tells you when it is degraded
Planned on stale price data, the schedule is flagged degraded. Past the price horizon, far-future costs read 0.00 and say so. The system would rather look uncertain than look confident and be wrong.
It survives your internet
Run records spool to local disk and drain when the connection returns. If the API is unreachable the controller keeps following its last known schedule and applies the fallback policy baked into it.
Where it does not help
Worth knowing before you install anything.
- Not for interactive work. Chat, live serving, anything a person is waiting on. If the start time cannot move, there is nothing here to optimize.
- One job at a time per box. The current version serializes; it will not pack two workloads into the same window.
- Savings depend on your tariff. On a flat rate there is nothing to shift into. The bigger the spread between your peak and overnight prices, the more this is worth.
Your next batch job does not have to run at peak.
Accounts are free during the open beta. Setup is an account, one registered workload, and a daemon on the box that does the work.