← Plugin catalog
Finance
Elecz - Electricity Prices
Sakari KorkiaAho v1.1.0
Publisher description
From the marketplace listing
Elecz provides real-time electricity prices and cheapest-hour recommendations across 40+ countries, plus electricity contract comparisons in supported markets. Get live spot prices, find the cheapest hours to run appliances or charge an EV, optimize flexible workloads to reduce electricity costs, and compare electricity contract options where available.
Language: English · Automatically detected from descriptions.
Files & skills
File archives
Plugin package8 files · 21.7 KBBrowse files →
Skill instructions
evaluate-electricity-contract12.5 KB
---
name: evaluate-electricity-contract
description: Evaluate whether to switch electricity contracts or whether spot or fixed electricity is the better option in a supported market. Use for electricity contract, tariff, provider-switching, and personalized contract-savings questions, not current-price facts or electricity-use timing.
---
# CONTRACT — Electricity Contract Evaluation
## Description (for discovery/routing)
Evaluates whether a user should switch electricity contracts, or which contract type suits them, using `best_energy_contract`. Unlike the timing-family skills, CONTRACT doesn't share their continuity/duration logic — its own risks are capability-mode handling, using the tool's full recommendation structure rather than a single summary field, and never treating backend default inputs (consumption, heating) as user-stated facts.
## When to use this skill
- "Should I switch electricity contracts?"
- "Is spot or fixed better for me?"
- "What's the best electricity contract available?"
- Explicit contract/tariff evaluation intent.
## When NOT to use this skill
- A pure price fact → **PRICE**.
- A timing/usage-pattern question with no contract framing → **TIMING**.
- EV/WORKLOAD-specific timing → **EV** / **WORKLOAD**.
- An undiagnosed general cost concern → **SAVE** may route here, but CONTRACT doesn't self-trigger on an ambiguous complaint alone.
## Tool
Use `best_energy_contract` only.
## Core invariant
**Never invent a missing input, and never treat a backend default as a user-stated fact.** The tool's `assumptions` object tells you the actual source of every input it used — defer to it rather than assuming what "typical" values should be.
## Capability modes
Branch directly on the `contract_comparison` field — this is a deterministic field check, not an inference from which other fields happen to be present.
**Mode 1 — `contract_comparison: "available"`**
Returns `best_spot`, `best_fixed`, `recommended` (with `contract` + `reason`), `decision_hint`, a top-level `reason`, an `action` object (`available`, `expected_savings_local_year`, `savings_basis`, `confidence`, `confidence_basis`, `status`, `action_link`, `provider`, `contract_id`), an `assumptions` object, and sometimes a `disclaimer`.
**Mode 2 — `contract_comparison: "not_available"`**
Use whatever tariff/price fields are actually present plus the `note` field. Response richness varies by market — don't assume any particular subset of fields beyond `contract_comparison` and `note` will be there; relay what's given. Never fabricate a recommendation or action link in this mode, and never apologize for a missing capability the market itself doesn't support — state the regulated structure plainly using the tool's own explanation.
## Recommendation integrity (Mode 1)
`decision_hint` (e.g. `spot_recommended`, `switch_recommended`, `stay_spot`, `consider_fixed`, `compare_options`) is a summary label, not the whole answer. Draw on the full object:
- `recommended.contract` — which contract, `recommended.reason` — why.
- `action.available` — whether an actionable switch exists at all.
- `action.expected_savings_local_year` + `action.savings_basis` — the estimate and what it's measured against.
- `action.confidence` + `action.confidence_basis` — relay the basis text (in your own words) alongside the number. It documents a simple heuristic, not a statistical measure — use it directly rather than inventing independent certainty language.
- `action.status`.
- Any `disclaimer` — surface it, don't drop it for brevity; it can materially affect whether the savings estimate is complete (e.g. excluding a regional grid fee).
**Consistency checks (apply on every Mode 1 response):**
- If `recommended`, `decision_hint`, the top-level `reason`, and `action` visibly disagree with each other, do not present a single confident recommendation. Surface the disagreement instead — state that a recommendation exists but the fields describing it don't agree, without picking one side, averaging, reconciling, or guessing which is right.
- Before presenting `action.action_link` as the routing destination, check that `action.provider` / `action.contract_id` match `recommended.contract.provider`/`.id`. If they disagree, do not present the action link as a valid next step — state that a recommendation exists but the action destination couldn't be verified, and never guess which provider or link is correct.
**Link integrity (applies whenever `action.action_link` is presented):**
Present `action.action_link` exactly as returned — verbatim, including every query parameter. Never strip, simplify, "clean up," reformat, shorten, or reconstruct the link, and never substitute a provider's general website or homepage URL in its place, even if the returned link looks long, unfamiliar, or contains tracking parameters. Those parameters are the attribution mechanism for the recommendation — altering or dropping them breaks it silently, with no visible error. This rule holds regardless of how the link is rendered (plain text, markdown link, button) — the underlying URL string itself must be untouched.
## Consumption and heating: check before calling, don't assume
The `assumptions` object (once the tool is called) states each input's actual source, e.g. `{"annual_consumption_kwh": 2000, "consumption_source": "zone_default", "heating": "district", "heating_source": "default"}` when unspecified, vs. `"user_provided"` when supplied. But don't wait for the tool call to decide whether to ask — determine this from the request itself first:
- **Personalized question** ("how much would I save?" or any request for a specific savings number) **with no annual consumption stated anywhere in the conversation** — ask for it *before* calling `best_energy_contract`, the same way TIMING/EV/WORKLOAD ask for a required input before calling `cheapest_hours` when it's needed to answer the specific question asked. Don't call the tool on a default first just to discover afterward that the answer needed to be personalized — that's a wasted call for a question you could already tell needed the real number. If the user says they don't know their consumption and wants a rough estimate anyway, that's fine — call with the default, but state the result explicitly as an assumption using the `assumptions` object's own values, never presented silently as their number.
- **Generic question, no personalization requested** ("is spot generally better than fixed right now?") — call the tool as-is; a `zone_default`-sourced answer is fine to present as a scenario ("for a typical ~2000 kWh/year household...").
- **Consumption already stated in the conversation** — call directly with it; no need to ask again.
- If, after calling, `assumptions.consumption_source` turns out to be `zone_default` on what was actually a personalized request (e.g. the intent wasn't obvious from phrasing alone), don't present the figure as personal — either ask for the real consumption before finalizing the answer, or clearly label the figure as a scenario estimate using the `assumptions` object's own values.
- **Heating**: the same ask-before-call principle applies when heating type would materially change the result — but with a limitation: `heating_source` can only ever say `"user_provided"` or `"default"`, and can't distinguish "the user explicitly said district heating" from "the user said nothing and district was assumed." If the user has actually stated their heating type earlier in the conversation, treat that as known regardless of what `heating_source` says post-call.
## Zone resolution (shared logic — do not improvise a different version here)
Resolve the electricity market in this order, stopping at the first that applies:
1. The explicit electricity location the question is actually about — this may differ from the user's physical location.
2. A location already established earlier in the conversation, if still relevant to this request.
3. Reliable product-provided location context, only if nothing more specific applies.
4. If none of the above resolves it reliably, ask one short question before calling the tool. Do not guess or use the tool's technical default zone as a resolved answer.
Zone persists by semantic continuity (the same target is still being discussed), not by a time limit — re-resolve only when the target changes or becomes ambiguous again.
## Missing-data handling
| Missing | Behavior |
|---|---|
| Zone | Resolve per shared hierarchy; ask if unresolved |
| Consumption (personalized question, not yet stated) | Ask for it before calling the tool; if the user wants a rough estimate anyway, call with the default and label the result as an assumption |
| Heating type (when it would change the result) | Check `assumptions.heating_source`, but also weigh any heating type the user has stated in conversation |
| `action` object absent (Mode 2) | Do not invent a recommendation or savings estimate; relay the tool's own `note`/available tariff fields instead |
| `recommended`/`decision_hint`/`reason`/`action` disagree | Surface the disagreement; don't pick a side |
| `action.provider` disagrees with `recommended.contract.provider` | Don't present the action link as valid; state the destination couldn't be verified |
## Output behavior
- Mode 1: state the recommendation, the reason, the savings estimate with its basis and confidence (via `confidence_basis`), any disclaimer, and the action link — never reduce this to just `decision_hint`. When the action link is presented, use `action.action_link` verbatim (see Link integrity above) — never a derived, shortened, or "cleaned" URL.
- Mode 2: state the regulated structure and the tool's own explanation for why switching/comparison isn't available, using whatever fields are actually present.
- Personalized savings claims: if consumption hasn't been stated, ask for it before calling the tool at all — don't call on a default and discover the gap afterward. If the user wants a rough estimate anyway, clearly label the figure as a scenario estimate, not their personal number.
- If a consistency check under Recommendation integrity fails (fields disagree, or provider/link mismatch), say so plainly rather than presenting a single confident answer.
## Examples
**Mode 1**
- "Should I switch?" with consumption already stated → call directly, full recommendation drawing on `recommended`/`action`/`assumptions`/`disclaimer`, not just `decision_hint`.
- "Is spot generally better than fixed right now?" (no personalization requested) → call the tool as-is; may use the `zone_default`-sourced scenario without asking, since `assumptions` already labels it as such.
- "How much would I save by switching?" with no stated annual usage anywhere in the conversation → ask for consumption *before* calling the tool, rather than calling with a default first and discovering the gap afterward.
**Mode 2**
- "Should I switch electricity providers?" in a regulated market with rich tariff data → explain the regulated structure using `contract_comparison: "not_available"` plus the `note` and available tariff fields; no invented recommendation.
- Same question in a market with only `spot_price` and `note` → explain the regulated structure from `note` alone; don't assume richer fields exist just because another market had them.
**Disclaimer and confidence**
- A response includes a grid-fee disclaimer → included in the answer, not dropped.
- Explaining `action.confidence` → use `action.confidence_basis` text rather than inventing independent certainty language.
**Consistency checks**
- `recommended`, `decision_hint`, `reason`, and `action` all agree → present the recommendation normally.
- Any of those fields visibly disagree → state that a recommendation exists but its fields don't agree with each other; don't present a single confident answer or guess which field is right.
- `action.provider` matches `recommended.contract.provider` → present the action link normally.
- They disagree → don't present the action link as a valid next step; say the destination couldn't be verified.
**Link integrity**
- `action.action_link` is `https://provider.example/switch?plan=abc&aff=elecz123` → presented exactly as-is, full query string intact.
- Assistant is tempted to show `https://provider.example` instead because it looks cleaner → not allowed; the affiliate/tracking parameters must survive.
**Negative (must route elsewhere, not answered by CONTRACT)**
- "What's the electricity price right now?" → PRICE, not CONTRACT.
- "Our bills have gotten so expensive lately." (no contract framing) → SAVE may route here later, but CONTRACT doesn't self-trigger on this alone.
find-best-electricity-time10.2 KB
---
name: find-best-electricity-time
description: Find the cheapest electricity hours or decide whether to use electricity now or wait in a supported market. Use for electricity timing and cheap/expensive judgments, not pure current-price facts, EV-specific charging decisions, workload scheduling, or contract questions.
---
# TIMING — Electricity Timing Decision
## Description (for discovery/routing)
Answers the electricity-price-relative decision: "is now a good time, or should I wait — and if so, for how long / until when?" This is a decision skill, not a data listing — always attempt an actionable answer to the timing question actually asked, without overstating certainty beyond what the data supports. Covers both present-moment judgment ("is it cheap now?") and forward-looking window-finding ("find me the cheapest hours"), as long as the requested task does not require reasoning owned by a more specific domain skill (such as EV or WORKLOAD) — a domain word alone, on a task that doesn't need that domain's reasoning, stays with TIMING.
## When to use this skill
- "Is electricity cheap/expensive right now?"
- "Should I use electricity now or wait?"
- "Is now a good time to run [a generic/unspecified appliance]?"
- "What are the cheapest hours today/tonight?"
- "Find me three cheap hours."
- "What's the cheapest N-hour window before [deadline]?"
- "When should I use electricity tomorrow?"
## When NOT to use this skill
- A pure current-price fact request with no relative judgment ("what's the price right now?") → **PRICE**.
- An explicit EV-charging context, where the task itself needs EV-specific reasoning (charging schedule, target SOC, departure time) → **EV**. A bare mention of "EV" on a task that doesn't actually need that reasoning (e.g. a generic timing question that happens to reference an EV in passing) stays with TIMING.
- A defined flexible operational load, where the requested task requires workload-specific scheduling reasoning (compute, industrial, business-scale scheduling) → **WORKLOAD**. A workload/domain mention alone does not override TIMING when the requested task only needs generic timing reasoning.
- A general/trend cost concern with no specific timing question ("bills have gotten so expensive") → **SAVE**.
- Contract or tariff questions → **CONTRACT**.
- A request to actually control or switch on a device → out of scope for the whole plugin. TIMING may state the best time to act, but must never imply it can carry out the action itself.
## Tool
Use `cheapest_hours` only. TIMING never calls `spot_price` — that's PRICE's tool.
## Core invariant
**Never invent a market, duration, deadline, or continuity requirement merely to complete an optimization.** Ask, or answer only what the available data actually supports — every rule below is an application of this.
## Zone resolution (shared logic — do not improvise a different version here)
Zone is a required input — TIMING cannot produce a meaningful answer without it, so resolve it before any tool call. Resolve in this order, stopping at the first that applies:
1. The explicit electricity location the question is actually about — this may differ from the user's physical location (e.g. asking about a home in Sweden while physically in Finland resolves to Sweden).
2. A location already established earlier in the conversation, if still relevant to this request.
3. Reliable product-provided location context, only if nothing more specific applies.
4. If none of the above resolves it reliably, ask one short question before calling the tool. Do not guess, and do not treat the tool's technical default zone as a resolved answer.
Zone persists by semantic continuity (the same target is still being discussed), not by a time limit — re-resolve only when the target changes or becomes ambiguous again.
## Duration, deadline, and continuity
- **Duration**: do not invent it. Ask only when a specific duration is required to answer the requested optimization. If the question can be answered usefully without assuming a task duration, do so without inventing one.
- **Deadline**: do not invent one — use only the horizon the request naturally implies ("tonight" → tonight, "tomorrow" → tomorrow). Ask only if an unstated deadline would materially change the optimization.
- **Continuity** (`cheapest_hours[]` vs. `best_window`): a distributable/interruptible task → `cheapest_hours[]`, never presented as a contiguous block. A task needing one continuous block of N hours → `best_window`, framed as "the lowest-cost available window for this duration," never as "N cheap hours" — if the window's average is high relative to the genuinely cheap hours, say so rather than calling it unconditionally cheap. If continuity is unspecified and doesn't materially affect the answer, default to `cheapest_hours[]`; if it would materially affect the answer, ask.
## `best_window` field handling
`best_window.end` is the start of the final slot, not the physical end of the covered interval (a 3-hour request returning `start: 21:00, end: 23:00` actually covers 21:00–00:00). Never present `end` as the session's physical end time — derive actual coverage from slot count. Resolve any user-facing clock time or deadline in the target zone's local time before converting it to the tool's hour-count parameters; never treat tool timestamps as already matching the user's stated local time.
## Capability states
1. **`available: false`** — relay the tool's own `reason` field. Do not improvise a reason, and do not fall back to `spot_price` as a substitute — if TIMING can't answer, say so rather than quietly answering a different question.
2. **`available: true`, `data_complete: false`** — give the best available answer, hedged (e.g. "based on partial data so far…"), not presented with full confidence.
3. **`available: true`, `data_complete: true`** — answer without the partial-data hedge.
## Present-moment decisions
Combine the current state with the next actionable option — never report the current state in isolation.
- Use `current_hour_is_cheap` / `current_hour_signal` / `current_hour_rank` for the "now" judgment.
- **Preserve the tool's own categorical state — don't upgrade it based on what's coming later.** `energy_state`/`current_hour_signal` values like `normal` or `medium` must not be reported as "expensive" merely because a cheaper hour exists later in the data. A cheaper time existing later is a *relative* fact (there's a better option ahead); the current price's own classification is a separate, *absolute* fact. Both can be said together ("prices are normal right now, but there's a cheaper window in about 3 hours") — but the categorical label itself must come from what the tool actually returned for the current hour, never inferred from the shape of the rest of the data.
- If now isn't good and the tool provides a next cheap period within the available data, use `hours_until_next_cheap` / `next_cheap_hour` to say when it starts. If the tool doesn't provide one within the published data window, say that the next better time can't be confirmed from the data available — never promise a next-cheap time the data doesn't actually cover.
- Apply the `data_complete` hedge above where relevant.
- Example shape: "Now isn't a great time — the next cheaper period starts in about 5 hours," not just "now is not cheap." Contrast: if `current_hour_signal` is `normal`, the correct shape is "prices are normal right now — there's a cheaper window later if you can wait," never "electricity is expensive right now."
## Output behavior
- State the resolved market on the first answer in a conversation, or whenever it changes or could otherwise be ambiguous. Don't repeat it on follow-ups clearly still about the same target.
- Make it clear through the content of the answer itself whether it's a present-moment judgment or a window recommendation — not with a separate meta-label ("This is a window recommendation..."). The phrasing should make the type obvious without announcing it.
- Never claim the ability to act (start/stop a device) — TIMING states timing only.
- The number of slots returned in `cheapest_hours[]` is a query/output choice controlled by the `hours` parameter, not evidence of the user's required duration — never imply "you should use electricity for these N hours" when no duration was requested; frame results as "these are the lowest-price hours available."
## Examples
**Positive**
- "Is electricity cheap right now?" → `cheapest_hours`, resolve zone, present-moment judgment + next-cheap-hour context if not currently cheap.
- "Find me three cheap hours tonight." → `cheapest_hours[]`, scoped to tonight, non-contiguous list.
- "What's the cheapest 4-hour window before 7 AM?" → `best_window`, framed as lowest-cost available window, not as four individually cheap hours.
**Negative (must route elsewhere, not answered by TIMING)**
- "What's the electricity price right now?" → PRICE, not TIMING.
- "Should I wait before charging my EV?" → EV, not TIMING (the requested task is EV-charging timing).
- "Electricity has gotten so expensive lately." → SAVE, not TIMING.
**Zone edge case**
- "I'm in Finland, but should I run the dishwasher at my apartment in Stockholm now?" → resolve to Sweden (the electricity location asked about), not Finland (the user's physical location); clarify the Swedish price zone if not otherwise resolvable.
**Data-quality / missing-input edge cases**
- No zone, no context at all → ask; never default to the tool's technical zone.
- `current_hour_is_cheap: false` → include next-cheap-hour context when the tool provides it within the available data window; otherwise state that the next better time can't be confirmed from the data available.
- `current_hour_signal: normal` (or `medium`) with a cheaper hour later in the data → report "normal," not "expensive." A better option existing later doesn't change what the current hour's own classification is.
- `best_window` requested at a size exceeding genuinely cheap hours → must not claim the whole window is "cheap."
- "Find me the cheapest time to run this job" with no stated duration → ask for duration rather than silently defaulting to `cheapest_hours[]`.
- "Cheapest hours today" → scope to today; do not silently substitute a 24h-forward default.
get-electricity-price6.54 KB
---
name: get-electricity-price
description: Get the current electricity price or spot price for a supported electricity market. Use for factual present-moment electricity price questions, not timing, cheap/expensive judgments, EV charging decisions, or contract comparisons.
---
# PRICE — Current Electricity Price
## Description (for discovery/routing)
Answers a single factual question: "What is the electricity price right now?" Returns the current wholesale spot price for a specified or resolved electricity market — nothing more. Does not judge whether the price is cheap or expensive, does not recommend waiting or acting, does not compare contracts. If the user's question requires any of those, this is not the right skill.
## When to use this skill
Use PRICE when the user wants a plain, present-moment price fact:
- "What's the electricity price right now?"
- "How much does electricity cost now?"
- "What's the current spot price in Germany?"
- "What's electricity trading at right now?"
- "What's the electricity price right now for my EV charger?" (a domain word is present, but the task is still a plain fact request, not EV-specific reasoning)
- "What's the current electricity price at our data center?" (same — domain named, but no scheduling/optimization reasoning required)
## When NOT to use this skill
- The user asks a *relative* judgment — "is it cheap/expensive right now?", "is now a good time?" → route to **TIMING**. `spot_price` has no cheap/normal/expensive classification. Do not invent one.
- "Should I use electricity now or wait?" → **TIMING**.
- A general or trending cost concern — "my bills have gotten so expensive lately", "electricity is ridiculous these days" → **SAVE**. This is not a present-moment fact request.
- Contract or tariff comparison, or switching providers → **CONTRACT**.
- A domain-specific question that actually needs domain reasoning (target SOC, deadline, scheduling a load) rather than a plain number — e.g. "Is now cheap for charging my EV?" → **EV**, not PRICE. The presence of a domain word (EV, data center, fleet, etc.) does not by itself redirect a plain fact request away from PRICE, and it does not by itself send a genuinely domain-reasoning question to PRICE either. What decides it is whether the task needs domain-specific reasoning to answer — not whether a domain word appears.
## Tool
Use `spot_price` only. Never call `cheapest_hours` from PRICE. Relative judgment and forward-looking reasoning are outside PRICE's scope.
## Zone resolution (shared logic — do not improvise a different version here)
Resolve the electricity market in this order, stopping at the first that applies:
1. An explicit electricity location stated in the request — this is the location the *price* is about, which may differ from where the user physically is.
2. A location already established earlier in the conversation, if still relevant to this request.
3. Reliable location context provided by the product/platform, only if nothing more specific applies.
4. If none of the above resolves it reliably, ask one short clarifying question. Do not guess.
Do not treat the tool's technical default zone as a user default. Zone persists across a conversation by semantic continuity (the same target is still being discussed), not by a message-count or time limit — re-resolve only when the target changes or becomes ambiguous again. Getting the zone wrong here is just as much a wrong answer as getting it wrong in a timing or contract decision, even though PRICE itself is a simple skill — do not simplify this logic because the rest of the skill is thin.
**Do not call `spot_price` with a guessed or default zone when the location is genuinely unresolved — ask first.** Calling the tool on a guessed zone "to get something" and only checking for ambiguity afterward is the failure mode this rule exists to prevent.
## Core invariant
**Never invent a market/zone, a staleness/confidence judgment, or a price interpretation merely to complete an answer.** Every rule below is an application of this.
## Data quality / freshness handling
`spot_price` returns `age_seconds`, `stale`, `source`, `fallback`, and `disclaimer`.
- If `stale: true` or `fallback: true`, say so plainly in the answer — do not present the number as live current-moment ground truth without that caveat.
- Surface the content of `disclaimer` in your own words whenever it materially affects how the number should be read (most commonly: this is a wholesale price, retail price includes taxes/transmission/distribution on top). Don't drop it for brevity when it matters.
- Do not invent your own staleness threshold from `age_seconds`. Rely only on what `stale` and `fallback` themselves indicate.
## Output behavior
- State the resolved market (and unit/currency) on the first answer in a conversation, or whenever the market changes or could otherwise be ambiguous. Don't repeat it mechanically on every follow-up turn that's clearly still about the same market ("what about now?").
- Only mention freshness/source context when it changes how the number should be read (stale, fallback, or a disclaimer that matters here). Don't pad a fresh, unremarkable answer with it.
- If the requested market/zone isn't covered by `spot_price`, relay what the tool actually returns (or say plainly that it can't be retrieved) rather than guessing a plausible-sounding number.
## Examples
**Positive**
- "What's the electricity price right now?" → `spot_price`, resolve zone, state price/unit/currency/market.
- "What's the current spot price in Germany?" → `spot_price` for DE, no judgment added.
- "What's the electricity price right now for my EV charger?" → `spot_price`, plain fact, no EV-specific reasoning added.
**Negative (must route elsewhere, not answered by PRICE)**
- "Is electricity expensive right now?" → TIMING (`cheapest_hours`), not PRICE.
- "Electricity has gotten so expensive lately, it's ridiculous." → SAVE, not PRICE.
- "Is now cheap for charging my EV?" → EV, not PRICE — this needs the timing/domain reasoning `spot_price` alone can't supply.
- "Should I switch electricity contracts?" → CONTRACT, not PRICE.
**Data-quality edge cases**
- Tool returns `stale: true` → flag staleness explicitly in the answer.
- Tool returns `fallback: true` → note the fallback explicitly rather than presenting it as a normal live read.
- Zone ambiguous or conflicting with the user's physical location (e.g. user is physically in Stockholm asking about Finnish electricity) → resolve to the *electricity location* actually asked about, not the user's physical location; ask if genuinely unresolved.
optimize-ev-charging12 KB
---
name: optimize-ev-charging
description: Optimize EV charging timing using electricity prices. Use when the user asks when to charge an electric vehicle, whether to charge now or wait, or how to schedule EV charging around a deadline, required charging duration, battery state of charge, or charger power.
---
# EV — Electric Vehicle Charging Timing
## Description (for discovery/routing)
Answers electricity-price-relative charging decisions for a stated EV context, at whatever level of specificity the user provides — from a simple "when's cheap to charge tonight?" through a fixed deadline, up to full duration/SOC-constrained optimization. EV is not "TIMING plus the word EV," and it is not a full EV energy calculator: Elecz supplies the price/timing signal only; the agent does arithmetic (e.g. kWh ÷ kW) on inputs the user actually supplies. EV must never invent a missing input — SOC, battery capacity, charging power, or duration — to complete an optimization it wasn't given enough information to solve.
## Core invariant
**A charging deadline tells EV when charging must finish. It does not tell EV how long charging takes.** These are two different pieces of information — never let one substitute for the other, and never derive a duration from a deadline alone.
## When to use this skill
Any "when should I charge my EV" question, at any of three specificity tiers, where the task genuinely involves EV-charging timing reasoning:
- "When should I charge my EV tonight?" / "Is now cheap for charging my EV?" (Tier 1 — no constraints given)
- "I need the car ready by 7 AM — when should I charge?" (Tier 2 — deadline given, duration unknown)
- "I'm at 30%, need 80% by 7 AM. When should I charge?" (Tier 3 — energy/SOC-constrained)
- A fleet or business-scale EV-charging task that requires EV-specific charging reasoning stays EV, not WORKLOAD — scale or business framing does not override the task-relevant EV domain.
## When NOT to use this skill
- A pure current-price question that happens to mention EV/charging, with no timing or optimization request → **PRICE** ("what's the price right now for my EV charger?" — the task is a plain fact request, not charging-timing reasoning).
- A generic timing question with no stated device or charging context → **TIMING** ("should I wait before charging?" with nothing identifying an EV).
- A general cost complaint the user associates with EV ownership, with no timing question yet → **SAVE** routes here; EV doesn't self-trigger on the complaint alone ("my bill is high because I got an EV" is SAVE's routing decision to make, not EV's to intercept).
- A domain-word mention alone, on a task that doesn't actually need EV-specific reasoning, does not pull the question into EV — the deciding factor is always whether the task needs EV reasoning (deadline, SOC, charging schedule), not whether the word "EV" appears.
## Tool
Use `cheapest_hours` only — the same tool as TIMING; there is no separate EV-specific tool. Never invent data the tool doesn't provide (no SOC, battery capacity, charging-power, or efficiency data exists in Elecz).
## Zone resolution (shared logic — do not improvise a different version here)
Same hierarchy as PRICE/TIMING: explicit electricity location → established conversation context → product-provided location → clarify. The charging location may differ from the user's stated physical location (e.g. charging at a second home or workplace in a different zone) — resolve to the charging location, not the user's presence. Ask before calling the tool if genuinely unresolved; never treat the tool's technical default zone as a resolved answer.
## Tier 1 — Generic charging timing (no constraints given)
Give a useful charging-context price signal without inventing duration or continuity: surface the cheapest available hour(s) within the horizon the request specifies or naturally implies (`cheapest_hours[]`) — the same rule TIMING uses for deadlines. If the request states or implies a horizon ("tonight," "tomorrow"), use it. If no horizon is stated or implied at all, don't invent one (e.g. don't default to "tonight") — use the tool's own default coverage as-is. The returned hour count is a query default, not a stated duration requirement — phrase the answer as "these are the lowest-price hours available," never as "you should charge for these N hours."
If the user might want the full charging session optimized as one continuous block, **offer** that explicitly rather than assuming it: "here are the cheapest charging hours available in that period; if you tell me how many hours of charging you need, I can find the best single window for that." Don't silently guess a duration or continuity requirement on their behalf.
## Tier 2 — Deadline-constrained charging (duration unknown)
A deadline is a horizon boundary, not a duration — see the core invariant above.
- Resolve the deadline in the **charging location's local time** before converting it to the tool's hour-count `window` parameter. Never treat a user-stated local clock time as if it were already UTC or as if it directly matches the tool's parameter units — compute hours-until-deadline in local time first.
- With duration unknown, use the deadline only to bound the search horizon and surface the cheapest available hour(s) before it. Do not construct a complete charging plan and do not call `best_window` with an invented duration.
- Ask for the required charging duration only when the user is specifically asking for the optimal timing of the *entire* charging session — deadline proximity alone is not a reason to ask.
## Tier 3 — Energy/SOC-constrained charging
This tier needs a charging *duration*, which Elecz doesn't have on its own. Duration confidence, strongest to weakest:
1. **Stated duration** ("it usually takes about 4 hours") — use as-is.
2. **Stated energy + charging power** ("I need 40 kWh, charger does 11 kW") — the agent calculates duration (kWh ÷ kW), not Elecz.
3. **SOC + battery capacity + nominal charger power** — an *estimate only* (ignores losses and charge-rate tapering near full). Present it explicitly as an estimate, not a guarantee.
If the user hasn't supplied enough for at least level 3, ask for the **minimum missing input set in one concise question** — not a multi-round interview (e.g. ask for battery capacity and charging power together, not one at a time). Never invent typical battery capacity, charging power, or efficiency figures.
### Rounding for non-integer required duration
`cheapest_hours`'s `hours` parameter is an integer — a required duration that isn't a whole number (whether **stated** directly by the user, e.g. "charging takes about 3.5 hours," or **derived** by the agent from kWh ÷ kW) can't be passed to the tool as-is.
- **Required duration** (stated or derived): preserve the actual duration value in what you tell the user, but round the *search* up (ceil) to the next whole hour of `hours` slots. Disclose this as conservative slot-level scheduling, not sub-hour optimization — e.g. "your ~3.5h charging need is optimized across four hourly price slots," never phrased as if a 3.5-hour window itself was found.
- **Deadline/search horizon**: never round in a way that admits slots beyond the user's actual deadline. If the deadline is 6h20m away, the horizon must not be extended to 7h to reach a clean integer — round the horizon down/conservatively if anything, never past the stated constraint.
- These round in opposite directions for opposite reasons: required duration rounds up to guarantee enough search coverage; horizon never rounds past what the user actually allowed.
## `best_window` field handling
`best_window.end` is the start of the final slot, not the physical end of the covered interval — a requested 3-hour window returning `start: 21:00, end: 23:00` actually covers 21:00–00:00 (three full hourly slots). Never present `end` as the physical end time of charging; derive the actual end of coverage from slot count when telling the user when charging will finish.
## Missing-data handling
| Missing | Behavior |
|---|---|
| Zone | Resolve per shared hierarchy; ask if unresolved — required |
| Duration/deadline (Tier 1) | Not needed — surface cheapest available hours; offer, don't assume, a full-session window if duration is given |
| Deadline only, duration unknown (Tier 2) | Use deadline as search horizon only; never construct a full plan or call `best_window` with an invented duration |
| Charging duration inputs (Tier 3) | Never invent capacity, power, efficiency, or duration; ask for the minimum missing input set in one question if below confidence level 3 |
| Non-integer required duration (stated or derived) | Preserve the actual duration; round the search up, round horizon conservatively (never past the deadline); disclose the rounding |
| `data_complete: false` | Hedge the answer, same as TIMING |
| `available: false` | Relay the tool's `reason`; never substitute another signal |
## Output behavior
- State the resolved market on the first answer in a conversation; don't repeat it mechanically on follow-ups about the same target.
- Tier 1: cheapest available hours, framed for charging, with an explicit invitation — not an assumption — to specify a duration for a full-session window.
- Tier 2: cheapest hours before the deadline, explicitly not presented as a complete charging plan; invite duration only if the user wants full-session optimization.
- Tier 3: show the derived duration and its confidence level (stated / calculated / estimated) briefly so the user can sanity-check it, then give the timing recommendation. If rounding was applied, state that explicitly.
- Never state or imply a specific cost estimate unless the user has supplied the numbers needed to compute it (kWh and price) — don't assume typical EV consumption figures.
## Examples
**Tier 1**
- "When should I charge my EV tonight?" → cheapest available hours tonight, offer full-session optimization if a duration is given, no SOC/capacity questions asked.
**Tier 2**
- "I need the car ready by 7 AM." (no duration stated) → deadline used as search horizon only; no full plan constructed; asks for duration only if the user wants the whole session optimized.
**Tier 3**
- Follow-up after an EV timing request: "It usually takes about 4 hours to charge from 30% to 80%." → use the stated duration directly, no further questions.
- "I need 40 kWh and my charger does 11 kW — when should I charge?" → agent derives ≈3.6h, EV rounds up to a 4-hour search window and states both the calculated duration and the rounding, phrased as "optimizing across four hourly price slots," never as a sub-hour-optimal 3.6h window.
- "I'm at 30%, need 80% by 7 AM." with no capacity/power given → asks for usable battery capacity and charging power together in one question; if later supplied, presents the resulting duration as an estimate, not a guarantee.
**Negative (must route elsewhere, not answered by EV)**
- "What's the electricity price right now for my EV charger?" → PRICE, not EV — plain fact request.
- "Should I wait before charging?" (no device stated) → TIMING, not EV — domain not explicit.
- "My bill is high because I got an EV." → SAVE routes this; EV doesn't self-trigger on the complaint alone.
**Fleet/scale**
- "We run 12 EVs — when should we charge the fleet overnight?" → still EV, not WORKLOAD — the task needs EV-specific charging reasoning regardless of fleet size or business framing.
**Discipline checks**
- EV must never state a typical/assumed battery capacity, charging power, consumption, or duration figure on its own initiative.
- EV must never call `cheapest_hours` with a non-integer `hours` value or silently truncate a stated or derived duration without disclosing the rounding.
- "Ready by 7 AM" at the charging location must be resolved in the charging location's local time, converted to an hours-until-deadline horizon — never treated as UTC.
- A `best_window` response with `start: 21:00, end: 00:00` for a 4-hour request must be conveyed as the full ~4-hour coverage the slot count implies, never as a 3-hour span read naively from `start`/`end`.
optimize-workload-electricity-cost14.4 KB
---
name: optimize-workload-electricity-cost
description: Optimize when or where to run a flexible operational workload to reduce electricity cost. Use for schedulable compute, industrial, or business-scale loads, including single-market scheduling and multi-zone placement comparisons based on electricity prices.
---
# WORKLOAD — Flexible Operational Load Scheduling & Placement
## Description (for discovery/routing)
Optimizes the timing — and, when explicitly asked, the placement — of a defined flexible operational load: compute, industrial, or business-scale consumption that can be scheduled or relocated to reduce electricity cost. It applies the shared Elecz timing rules and adds operational-load routing plus multi-zone placement logic.
## Core invariant
**Elecz supplies the price/timing signal only. It never invents a missing load parameter (power draw, duration, efficiency, currency conversion rate) to complete a calculation or a comparison.** The agent does arithmetic on inputs the user actually supplies — same principle as EV's Tier 3.
## Owned intent
"When (or where) should this defined flexible operational load run, to minimize electricity cost?" — requires a stated capacity/load that can be scheduled as an operational unit, not a single household appliance.
## Operational-load boundary (WORKLOAD vs. TIMING)
The distinguishing factor is not device type or a 1-vs-many count — it's whether the user presents a defined, schedulable operational capacity to optimize, as opposed to a simple "when should I use electricity" question.
- "When should I run my washing machine?" → **TIMING** (single appliance, no operational framing).
- "100 washing machines at a laundromat — when should we run them?" → **WORKLOAD** (defined operational capacity).
- "Run this 500 kW workload for four hours" → **WORKLOAD** (explicit compute/industrial load).
## When NOT to use this skill
- A single unspecified appliance with no operational framing → **TIMING**.
- An EV-charging task that requires EV-specific charging reasoning → **EV**, regardless of fleet size or business framing. A bare EV mention does not override the actual task — WORKLOAD should never claim a fleet-charging question just because of its size.
- A general/undiagnosed cost concern → **SAVE** routes here only once the user has named a flexible load; WORKLOAD doesn't self-trigger on a bare complaint ("our bill is high" alone stays with SAVE until a schedulable load is named).
- A request to actually move or start the workload → out of scope for the whole plugin. WORKLOAD states timing/placement guidance only, never actuation.
## Tool
Use `cheapest_hours` only — same tool as TIMING/EV. No separate WORKLOAD-specific tool exists.
## Zone resolution (shared logic — do not improvise a different version here)
For every target location, resolve the electricity market before calling `cheapest_hours`: explicit electricity location the question is about → a location already established earlier in the conversation, if still relevant → reliable product-provided location context, only if nothing more specific applies → if none of the above resolves it reliably, ask before calling the tool. Never treat the tool's technical default zone as a resolved answer. In a multi-zone request, resolve every candidate location independently — don't let one resolved zone stand in for another. Zone persists by semantic continuity, not a time limit — re-resolve only when the target changes or becomes ambiguous again.
## Duration and deadline
Do not invent a duration or deadline. Use only constraints the user states or naturally implies. Resolve any user-facing deadline in the target electricity location's local time before converting it to the tool's hour-count parameters — never treat a stated local clock time as if it were already in the tool's units. A non-integer required duration (stated or derived) rounds the search up to enough whole-hour slots while preserving the actual duration value in the answer; a deadline/search horizon must never be rounded in a way that admits execution beyond the user's stated constraint — these round in opposite directions for opposite reasons. In multi-zone placement, resolve duration and deadline per candidate zone's own local time before Gate 2.
## Single-zone scheduling (inherited from TIMING — do not re-derive)
- Distributable load → `cheapest_hours[]`.
- Load that must run as one unbroken block → `best_window`, with the same caveats as TIMING/EV: `end` is the start of the final slot, not the physical end; a window's average price is not "every hour in it is cheap." Non-integer duration rounding is covered above.
## Capability states (single-zone and per-candidate in multi-zone)
Same three states as TIMING/EV, checked for every zone involved:
1. **`available: false`** — relay the tool's own `reason`. Never substitute `spot_price` or another signal.
2. **`available: true`, `data_complete: false`** — the zone is usable, but any answer drawing on it must be hedged (e.g. "based on partial data so far") rather than presented with full confidence.
3. **`available: true`, `data_complete: true`** — no hedge needed.
`data_complete: false` does **not** by itself make a zone unavailable — that's a Gate 1 (Capability) matter. It's a confidence qualifier that carries forward into whatever conclusion depends on that zone. In cross-zone placement specifically: if one candidate has `data_complete: false` and passes Gates 1–2 anyway, a placement conclusion involving that zone must be explicitly qualified as based on partial data for that zone — never presented as a fully resolved winner when one or more compared candidates have incomplete data. This is the existing partial-data invariant applied across zones, not a new gate.
## Load arithmetic
The agent computes cost/energy figures from user-supplied inputs only (e.g. 500 kW × 4 h = 2,000 kWh, then × price for an estimated cost). Never invent a missing power draw, duration, or efficiency figure to complete a calculation.
## Multi-zone: two distinct sub-intents — do not conflate them
### A. Per-zone scheduling (no comparison requested)
"Find the best four-hour window for this workload in Germany and Finland tonight." → the user wants each zone optimized independently. This is just parallel single-zone `best_window` calls — **no comparison or "winner" is required or implied.** Present each zone's result on its own terms.
### B. Cross-zone placement (a comparison is explicitly requested)
"Should I run this 500 kW four-hour job in Germany or Finland tonight?" / "Where should I run this — Germany or Texas?" → the user is explicitly asking WORKLOAD to pick a cheaper location. This requires passing three gates, **in order**, before any placement recommendation. Do not skip ahead to Gate 3 because Gates 1–2 look like they'll obviously pass — check them explicitly every time.
**Gate 1 — Capability.** Does `cheapest_hours` return `available: true` for every candidate zone?
- If any zone returns `available: false`, do not silently drop it and declare a winner among the rest. A surviving candidate is not automatically a winner when its comparator couldn't be evaluated.
- With exactly two candidates and one fails: state plainly that one zone can be evaluated and the other can't, so which is cheaper can't be determined — never declare the evaluable zone the winner by default.
- With three or more candidates, a partial ranking among the evaluable zones is fine — but state it as partial, not as resolving the original full comparison.
- Never fall back to `spot_price` for a zone `cheapest_hours` can't evaluate — that would be answering a different question, not filling the gap.
**Gate 2 — Feasibility.** Can each surviving zone actually produce a window sized to and optimized for the *same* requested duration/deadline?
- A 3h `best_window` in one zone and a 6h one in the other, for a stated 4h workload, are not "two valid results to compare" — the 3h zone fails to fit the requirement, and the 6h result isn't automatically valid either just because 6h exceeds 4h; it must actually be the tool's answer to a 4h request, not a longer window being reinterpreted as covering the need. Exclude or flag any zone whose result doesn't genuinely match the requested duration before any cost comparison.
- **Execution horizon alignment**: if the user gives an absolute constraint (e.g. "between 18:00 and 06:00 UTC"), use it directly. If they only say "tonight," local-"tonight" in each zone's own local time may not represent the same operational window — state that alignment as an assumption explicitly, don't resolve it silently.
**Gate 3 — Comparability.** Even when both zones pass Gates 1–2, a lower number isn't automatically "cheaper" until:
- **Currency/unit are compared from the actual `cheapest_hours` responses being used** — not a separate `spot_price` call, which risks comparing a different signal than the one driving the placement decision. If currencies differ, convert only with a reliable current FX source available to the agent — never invent or assume an exchange rate. Without one, don't declare a numeric cross-currency winner: present results separately per zone and state that normalization would be needed.
- **Cost basis is the same** (wholesale, per Elecz's `disclaimer` — retail adds transmission/distribution/taxes that vary by market). Phrase any recommendation at the right certainty level:
- Allowed: "Based on Elecz's wholesale price signals, Germany is cheaper for this workload window."
- Not allowed: "Germany will cost less to run" (implies a verified all-in cost that wholesale data alone can't support).
- If the user specifically asks for actual/all-in cost and only wholesale data is available, say the all-in winner can't be confirmed from this data — optionally still offer the wholesale-only comparison alongside that caveat, but don't answer the all-in question as if resolved.
Only after all three gates are passed — or their limitations explicitly disclosed — may WORKLOAD say something like "Zone A is cheaper than Zone B for this workload, under these assumptions."
## Missing-data handling
Inherits TIMING/EV's zone/duration/deadline handling (see Zone resolution above and Single-zone scheduling). `data_complete`/`available` behavior is covered in Capability states above. Additions specific to cross-zone placement:
| Missing | Behavior |
|---|---|
| Currency alignment across zones | Compare from the actual `cheapest_hours` responses in use; convert only with a reliable FX source available to the agent — never invent a rate; otherwise present per-zone results separately and state normalization is needed |
| Feasible window in one candidate zone | Treat as a Gate 2 feasibility failure for that zone, not a valid-but-different data point |
| Comparable execution horizon | If "tonight" or similar isn't resolved to a shared absolute window, state that as an assumption, not a silently resolved fact |
## Output behavior
- Per-zone scheduling: present each zone's result independently — no forced ranking.
- Cross-zone placement: make the result of each relevant gate clear through the answer itself — don't mechanically announce gate names when every check passes ("Capability: passed. Feasibility: passed..."). Explicitly surface a gate by name only when it blocks or materially qualifies the comparison (e.g. "Germany can be evaluated, but Texas doesn't have compatible timing data, so I can't determine which is cheaper" — the capability check is evident from the answer without naming "Gate 1"). If any compared candidate has `data_complete: false`, say so as part of the qualification, not as a separate mechanical flag. Disclose currency handling and frame wholesale-only comparisons as such rather than as guaranteed all-in cost outcomes.
- Never claim the ability to actually move or start the workload — timing/placement guidance only.
## Examples
**Single-zone**
- "Run this 500 kW workload for four hours before 7 AM — cheapest time?" → single-zone `best_window`, no new WORKLOAD-specific logic beyond inherited TIMING behavior.
**Per-zone (no comparison)**
- "Find the best four-hour window for this workload in Germany and Finland tonight." → two independent results, no declared winner.
**Cross-zone, both available and feasible**
- "Should I run this 500 kW four-hour job in Germany or Finland tonight?" → both pass Gate 1; Gate 2 confirms both zones actually produced a window for the requested 4h (not a longer window reinterpreted); Gate 3 checks currency (both EUR, no conversion needed) and states the wholesale-basis caveat — only then a zone may be recommended.
**Gate 1 failure**
- "Germany or Texas tonight?" (Texas `cheapest_hours` unavailable) → states it can't determine which is cheaper; does not declare Germany the winner by default; does not fall back to `spot_price` for Texas as a substitute.
**Gate 2 failure**
- Workload needs 4h; one zone's best available window is only 3h → that zone is excluded as infeasible, not presented as a different-but-valid comparison point.
**Partial data in a compared candidate**
- Germany passes Gates 1–2 with `data_complete: true`; Finland passes with `data_complete: false` → a placement conclusion may still be given, but must explicitly note that the Finland side is based on partial data — not presented as a fully resolved comparison.
**Gate 3 — currency mismatch, no FX source**
- Two zones return different currencies, no reliable FX source available → results presented separately per zone; states normalization would be required; no invented exchange rate, no declared winner.
**Gate 3 — all-in cost question**
- "Which location will actually cost my company less?" with only wholesale data available → states the all-in winner can't be confirmed from this data; may still offer the wholesale-only comparison as a separate, clearly labeled data point.
**Execution horizon ambiguity**
- "Germany or Finland tonight?" with no absolute time constraint given → treats "tonight" alignment across zones as a stated assumption, not a silently resolved fact.
**Negative (must route elsewhere, not answered by WORKLOAD)**
- "When should I run my washing machine?" → TIMING, not WORKLOAD — no operational framing.
- "We run 12 EVs — when should we charge overnight?" → EV, not WORKLOAD — the task requires EV-specific charging reasoning regardless of fleet size.
- "Our factory bill is getting ridiculous." (no load named yet) → SAVE, not WORKLOAD — routes here only once a schedulable load is named.
resolve-electricity-cost-concern12.5 KB
---
name: resolve-electricity-cost-concern
description: Resolve general or unclear electricity bill and cost concerns to the right Elecz capability. Use for electricity bill complaints, rising electricity costs, or questions about lowering an electricity bill when the user has not yet specified whether the issue is price, timing, EV charging, workload scheduling, or an electricity contract.
---
# SAVE — Electricity Cost Concern Router
## Description (for discovery/routing)
An intent resolver for a general, undiagnosed, or ambiguously-phrased electricity cost concern — trend language, bill complaints, "how do I save money," or emotionally-framed cost anxiety — where the user hasn't already specified which kind of question they have. SAVE is a fallback classifier, not a preferred first stop: recognize the concern, determine whether an Elecz signal can address it, and either resolve it directly from context already given, ask one clarifying question, route to the owning skill, or state plainly that this is outside what Elecz can determine.
## When to use this skill
- "Electricity has gotten so expensive lately, it's ridiculous."
- "Our company's electricity bill has doubled."
- "How can I lower my electricity bill?"
- "I can't keep up with these electricity bills."
- Any cost complaint or savings question where the phrasing doesn't already point to a specific capability.
## When NOT to use this skill
A direct skill's owned intent always wins outright over SAVE — SAVE does not intercept these:
- A pure price fact → **PRICE**.
- An explicit timing decision → **TIMING**.
- An explicit EV or WORKLOAD domain with a timing/optimization ask → **EV** / **WORKLOAD**.
- An explicit contract/switching intent → **CONTRACT**.
This is about the phrasing of the request itself, not a two-step "always go through SAVE first" process — if the very first message already carries an EV-specific or WORKLOAD-specific actionable component per the shared domain-reasoning rule, it can go directly to that skill without passing through SAVE at all. SAVE owns the *undiagnosed* concern, not every mention of cost.
## Tool
**SAVE itself calls no Elecz MCP tool to answer the concern as SAVE.** Its own job is classification and routing, not signal retrieval — it never reaches for `cheapest_hours` or `best_energy_contract` as a shortcut to produce an answer while still acting as SAVE. This is different from continuing into the resolved skill's own flow (see Route below): once the target is resolved, any tool call that happens is that skill's own logic running, not SAVE improvising with the tool "for convenience." Do not pre-answer with a guess at what the target skill would say instead of actually becoming that flow.
## Core invariant
**SAVE must never default to CONTRACT — or any other skill — as a generic fallback when the concern is ambiguous.** Every destination must be actively earned by something in the concern itself (a stated cause, a named flexible load, a tariff complaint, an explicit switching interest) or by the user's own answer to a clarifying question — never reached for as "the safest guess."
## Decision flow: Recognize → Resolve → Clarify → Route
### Resolve from existing context
If the user has already supplied enough to identify the right target, route directly — don't re-ask what's already been said. Once SAVE is active for an undiagnosed concern, use whatever context is already present in that concern to choose the downstream skill: a stated cause ("...because I got an EV"), a named flexible load ("our GPU cluster," "production runs we can move"), or a tariff complaint, all resolve directly without a clarifying question.
Route on the problem the user actually states, never on an inferred profile (consumer vs. developer vs. business) — a GPU-cluster complaint routes to WORKLOAD because a flexible compute load was named, not because it "sounds like a developer."
### Clarify when necessary
If there's genuinely not enough to route, ask **one** concise question at a time — never a multi-question interview, never an open-ended "can you tell me more?" Ask a question that distinguishes the plausible remaining destinations given whatever context has already been supplied — don't mechanically reach for the same fixed pair every time. A zero-context question ("how can I lower my bill?") is well served by a plan-vs-usage-timing framing; a richer context (e.g. a data-center cost complaint) should let the question reflect what's already known rather than ignoring it in favor of a generic template.
Keep offered options neutral — don't present one as more likely without evidence, even when it's a plausible guess like CONTRACT. If the user's answer still leaves it unresolved, a second round of clarification is fine — the constraint is one question per turn, not one question total.
### Route
Resolve to exactly one of the seven end states below. When the target is a downstream skill (not CLARIFY/OUT OF SCOPE), hand off by continuing directly into that skill's own flow in the same response — resolving the destination is not the end of the turn. If the owning flow already has what it needs, execute it (retrieve the signal, give the answer). If exactly one genuinely required input is still missing, ask for it directly, the way that skill itself would. If the capability itself is unavailable for the resolved target, state that boundary directly. Don't stop at naming the destination ("this routes to CONTRACT"), and don't wait for a user acknowledgement ("okay") before proceeding once the target and any required input are already known.
## End states
SAVE resolves to exactly one of: **PRICE · TIMING · EV · WORKLOAD · CONTRACT · CLARIFY · OUT OF SCOPE.**
### CLARIFY
Elecz may be able to help, but which capability isn't yet clear from what's been said. Ask one question; don't guess, don't default to CONTRACT.
- "Our company's electricity bill has doubled." → no domain, no timing cue, no flexible-load cue, no contract cue — ask.
### OUT OF SCOPE
The actual question is outside what any Elecz capability can determine, regardless of further detail. State the limitation plainly — don't ask a clarifying question that implies more detail would resolve it. Do not ask for more information in an attempt to resolve the original question; a related Elecz-answerable question may be offered separately, but make clear it's a different question, not a clarification path for the original one.
- "Why has my electricity consumption doubled?" → consumption-volume diagnosis is outside PRICE/TIMING/EV/WORKLOAD/CONTRACT entirely; no amount of follow-up changes that.
These stay distinct because the correct next action differs: CLARIFY invites more input, OUT OF SCOPE doesn't.
## User-supplied causal context
When the user supplies their own hypothesis about the cause ("my bill is high because I got an EV last month"), route on that stated association — no need to re-diagnose or verify it. But never assert the causal claim as a confirmed fact ("the EV caused your bill increase") — SAVE hasn't seen the user's consumption data. The internal logic is *the user associates the increase with EV charging → EV charging is an actionable, routable component → route to EV*, not *EV is confirmed as the cause*.
## Zone handling
SAVE doesn't need zone to classify and route — zone resolution happens in whichever downstream skill SAVE hands off to. Don't ask for zone before routing unless the routing decision itself genuinely depends on it (rare — routing is about intent, not location).
## Explicit non-triggers / anti-scope-creep
- SAVE never becomes a general electricity-savings advisor. It doesn't offer generic tips (unplug devices, insulate your home) that aren't backed by an Elecz signal — an unresolvable concern is OUT OF SCOPE, not an invitation to give generic advice instead.
- SAVE never re-derives a price/timing/contract answer itself instead of handing off to the owning skill.
## Output behavior
- When routing, continue directly into the resolved skill's own flow in the same response — announcing the destination is not the end of the turn. Execute if the owning flow already has enough information; ask for the one genuinely missing required input if it doesn't; state a capability boundary directly if the capability itself is unavailable. Don't pre-answer with a guess at what the target skill would say instead of actually applying its logic, and don't stop at describing the route.
- When clarifying, ask one concise question with concrete, neutral options shaped by the context already given — not a menu of all five downstream skills, and not always the same fixed pair.
- When stating OUT OF SCOPE, state the limitation plainly. Don't ask anything aimed at resolving the original question. A related but answerable question may be offered explicitly as a separate, clearly distinct option rather than leaving a dead end (e.g. "I can't tell you why your consumption increased, but as a separate matter, I can check whether your current plan or usage timing is costing you more than it should — want either of those?") — this is not a clarification of the original question.
## Examples
**Resolve directly from context**
- "My bill is high because I got an EV last month." → route to EV based on the user's stated association; SAVE does not assert that the EV caused the increase and does not pre-decide EV's downstream reasoning (SAVE's job ends at the handoff — which tier EV treats this as is EV's decision, not SAVE's to make in advance).
- "Our GPU cluster is costing us a fortune in electricity." → routes to WORKLOAD — a flexible compute load was named, not inferred from a "developer" profile.
- "Our factory costs are ridiculous, we can move some production runs around." → routes to WORKLOAD — a schedulable load was stated.
- "Should I switch electricity contracts?" (arriving via SAVE-adjacent phrasing) → routes to CONTRACT — explicit tariff/switching intent.
**Handoff continues immediately — doesn't stop at naming the destination**
- A data-center cost concern resolves to a 500 kW × 4h flexible compute workload → resolves to WORKLOAD and, in the same response, either runs the scheduling if the market is already known or asks directly for the market/zone — not "That routes to WORKLOAD" followed by waiting for the user to ask what's needed next.
- A fixed-price contract with no ability to shift usage → resolves to CONTRACT and, in the same response, asks directly for the country/market needed for `best_energy_contract` (or proceeds if already known) — not stopping at "this routes to CONTRACT."
- User corrects an unsupported market ("I meant Finland" after Latvia) → proceeds immediately with the CONTRACT flow for Finland in that same response, without waiting for the user to confirm with "okay" first.
**CLARIFY**
- "How can I lower my electricity bill?" with zero other context → ask, framed around plan vs. usage timing.
- "Our company's electricity bill has doubled." → ask one question; no domain, timing, load, or contract cue present.
- "My electricity bill doubled and I don't think I'm using more electricity." → ask, offering CONTRACT as one neutral option alongside others (e.g. plan/tariff vs. usage timing) — never phrased as the more likely cause.
- "I can't keep up with these electricity bills." (emotionally framed, no domain) → ask; don't misroute to PRICE on the word "bills," and don't leave it unaddressed.
- "Our electricity costs at the data center have exploded." → ask, but let the question reflect the operational context already given (e.g. whether load scheduling is possible) rather than defaulting to the generic plan-vs-timing pair.
**OUT OF SCOPE**
- "Why has my electricity consumption doubled?" → state the limitation plainly; no clarifying question implied.
**Negative (must not happen)**
- SAVE responding to an ambiguous concern with generic non-Elecz advice ("try using less power," "check for a more efficient appliance") instead of routing or reaching CLARIFY/OUT OF SCOPE.
- SAVE defaulting to CONTRACT for an unresolvable concern just because it sounds like a safe general answer.
- SAVE calling `cheapest_hours` or `best_energy_contract` itself, as SAVE, to produce an answer instead of continuing into the owning flow.
- SAVE stopping after announcing the destination ("this routes to WORKLOAD" / "the actionable path is CONTRACT") without continuing into that skill's execution in the same response.
- SAVE waiting for a user acknowledgement ("okay," "yes, proceed") before continuing once the target and any required input are already known.
Package details
Publisher declarations from the archived package. These are separate from our research and the live service's terms.
- Package author
- Sakari KorkiaAho
Package observed Sep 30, 2026.
Technical details
- First seen
- Sep 30, 2026 · 22:02 UTC
- Last seen
- Oct 1, 2026 · 18:00 UTC
- Collection status
- Collected
plugin_asdk_app_6a24c971acc48191bb99f2a694d24fbf
Download plugin data (JSON)