0% 5h quota used · resets in 2h live · 08/09/2026 12:04 CEST

Germany

Workspace countries/de/ — a market, with its own goals and its own money.

Runs 369
last 4h ago
Failed 55
14.9%
Spent $4,411
API-equivalent, all time
Open questions
no decisions.md in this workspace

Guardrails

countries/de/country.yaml — every run is admitted against these
Spent today $52.65
$52.65ceiling $500
Spent this month $1,510
$1,510ceiling $4,000
Cash this month $0
$0ceiling $50.00
Agent runs today 3
3ceiling 40
On exceed
alert reported and carried on — API-equivalent dollars are a quota proxy, not money
A task may declare
autonomy autonomous · at most 600 turns · at most 240 min
Per-run ceiling
$100 — alert only, a finished run is already spent
Warns at
80%
Refused so far
nothing has been refused
Declared, not enforced
outbound-email, form-submission
Read country.yaml
# Germany. Field reference: ../COUNTRY.md. Falls back to ../defaults.yaml.

identity:
  name: Germany
  domain: energiemarie.de
  language: de-DE

guardrails:
  autonomy_allowed: [autonomous]
  turns_max: 600                       # wasserversorger-discover sits exactly here
  minutes_max: 240
  budget:
    run_max_usd: 100
    daily_max_usd: 500
    monthly_max_usd: 4000
    monthly_spend_max_usd: 50            # real money; 0 while this country is on the subscription
    runs_per_day: 40
    on_exceed: alert

  # Inert until phase 3 — the two rules that matter most for this country are
  # "research only, never contact anyone" and "never edit seed.csv".
  forbid: [outbound-email, form-submission]

Campaigns

netzbetreiber 516 operators answered
wasserversorger 100.0% of the population
TaskDoesPolicyNextLast 12Spent
netzbetreiber-enrichResearch German grid operators (Netzbetreiber) and enrich the campaign roster with contact emails and portal details.autonomouson demand $344
netzbetreiber-send-dailySend the next wave of up to 50 outreach emails to German grid operators from the campaign roster. Deterministic script, no LLM.autonomousin 6d $0
netzbetreiber-push-contentsUpsert normalized findings into the contents repo (german_grid_operators). Deterministic script, no LLM; never touches review_status.autonomousin 6d $0
netzbetreiber-preisblattFind, download and extract the published §14a Preisblatt from the websites of German grid operators that never replied to the outreach.autonomouson demand $0
wasserversorger-discoverDiscover which German water suppliers exist and which municipalities each serves — the population-weighted coverage sweep that builds the Wasserversorger roster.autonomouson demand $1,881
wasserversorger-enrichEnrich German water suppliers (Wasserversorger) with contact details and the published water-analysis URL, and append results to the campaign JSONL.autonomousin 26m $1,891
netzbetreiber-repliesTriage new replies from German grid operators and extract data from their answers, then send the queued follow-ups and reminders via the guarded sender.autonomousin 1h $295

Spend by month

2026-07: $3642026-08: $2,5372026-09: $1,510 070809

The brief this workspace runs on

countries/de/CLAUDE.md · every run reads it first
Read CLAUDE.md

Country OS — Germany

Unlike tn/fr, this country dir does not manage a site. It runs data-collection campaigns for the German market (project "Smart research", with Stefanie Schäffer/SEO).

Current campaign: netzbetreiber

Goal: contact data for ~850 German electricity grid operators (Stromnetzbetreiber), to later request their §14a EnWG module prices. Files live in campaigns/netzbetreiber/:

  • seed.csv — Stefanie's MaStR export (source of truth for the list; key: MaStR-Nr.). Read-only: never edit this file.
  • enrichment.jsonl — one JSON record per researched operator, append-only. A re-research appends a new record; exports take the latest record per MaStR-Nr.
  • export_csv.py — renders enrichment.csv from the JSONL for import into the team's Google Sheet.

Hard rules

  1. Never invent contact data. A website counts only if verified official (the Impressum names the operator or its Stadtwerke parent). An email counts only if found on the operator's own site or its public MaStR record — never guessed from patterns like info@domain. If nothing verifiable is found, record contact_status: "no_contact_found" — an honest gap beats a wrong address.

  2. Never contact anyone by hand. No form submissions, no hand-written emails, not even "test" ones. Enrichment and discovery tasks are research-only. One exception, and it is not a loophole: the netzbetreiber campaign sends §14a follow-ups through campaigns/netzbetreiber/followups.mjs send, a deterministic script the netzbetreiber-replies skill runs at the end of every pass (its step 7). It only mails drafts already in followups-proposed.jsonl, it self-skips unless the mailbox is fully triaged, and it re-checks every draft against current data before SMTP (do_not_contact / data already complete / operator replied since drafting → superseded). Running it exactly as step 7 directs is expected and required — withholding it is the deviation. What stays forbidden is composing and sending mail yourself, outside that script. (Reconciled 2026-08-24: this rule predated the sending stage, and its old "this task family never contacts anyone" wording made runs flip-flop on step 7.)

  3. Anti-bot policy (decided by Frédéric 2026-07-20): simple challenge questions (arithmetic like "addieren Sie 1 und 6", basic quiz fields) may be answered when sending a legitimate inquiry. reCAPTCHA/hCaptcha/Turnstile/Cloudflare challenges and image captchas are never solved or bypassed — those operators get the email channel or the human queue. Honeypot ("leave empty") fields must never be filled.

    One exception, for documents an operator sent us (decided by Frédéric 2026-08-29). A URL that appears in an operator's own reply may be opened with a real browser engine, and the document behind it downloaded, for that operator only. This is retrieval of material handed to us in correspondence, not discovery — the operator chose the address, and the §14a figures behind it are publication-obliged under EnWG anyway. A challenge that resolves on its own when an ordinary browser loads the page is allowed to resolve. A cookie-consent banner may be answered, and is always answered by refusing everything optional — that is a truthful answer about tracking, not a click-through to make the page work.

    What stays forbidden is unchanged and applies here too: no captcha is ever solved, answered, or sent to a solving service; no login or paywall is passed; no honeypot is filled; nothing is submitted; and no URL we found ourselves is fetched this way. The browser must be an ordinary one — no stealth plugin, no fingerprint patching, no solver service, and browserless's own stealth launch flag stays off. Those exist and they work; using them is what turns "the page loaded normally" into "we defeated a control", which is the thing this rule is for. If a page needs any of that, it does not "resolve on its own" and the operator goes to the human queue, exactly as before.

    The preconditions are machine-checked in campaigns/netzbetreiber/fetch_reply_doc.mjs, never left to a run's judgment: the URL came out of a message whose mastr_nr matches, its host is the operator's own domain or a statutory portal (enwg-veroeffentlichungen.de), the request is a plain document GET, and do_not_contact.txt is refused outright. Fetching a link by hand bypasses all four, which is why the skill tells you to run the script rather than curl the URL yourself.

    Second exception, for Preisblätter published on the operator's own website (decided by Frédéric 2026-09-01). The clause above says "no URL we found ourselves is fetched this way". For this campaign's §14a price sheets, that no longer holds, and the reason is the operators' own answer: Stefanie phoned the silent ones and was told, over and over, "das finden Sie auf unserer Website". Three email rounds got no reply, the phone round got a redirect to the website, and §14a figures are publication-obliged under EnWG. So we read the website — both with a plain GET and, where a WAF stands in the way, with an ordinary browser engine.

    The host rule is what keeps this from becoming general crawling, and it is unchanged: every URL fetched must sit on the operator's own domain (their verified website, their email domain, or a brand-sharing sibling per sameOperator()) or on enwg-veroeffentlichungen.de. A web search may be used to locate a Preisblatt, but the URL it returns is subject to the same check — hand it to hunt_preisblatt.mjs --mastr … --url …, which enforces it, rather than fetching it yourself. A hit on a third-party host is refused, not argued about; when the search finds nothing on their own domain, go back to the operator's site and look there.

    Everything the first exception forbids stays forbidden here, without exception: no captcha is solved, answered or outsourced; no login or paywall is passed; no form is submitted; no honeypot is filled; the browser stays ordinary, with browserless's stealth flag off. Cookie banners are answered by refusing everything optional, as above. A page that does not resolve on its own goes to the human queue. What we are allowed to do is read what an operator chose to publish; we are not allowed to get past anything they put in the way.

    hunt_preisblatt.mjs performs the discovery and enforces the host rule and do_not_contact.txt; a URL it cannot turn into a document lands in fetch-queue.jsonl, which fetch_browser.mjs drains under this same rule.

  4. Record a source for every field group so freshness re-checks are possible later.

  5. As few comments as possible in the code you ship. A comment says why, and only when the reason is genuinely unusual — something a competent reader could not reconstruct from the code itself. Never narrate what the code does, never restate a name, never gloss a self-describing constant. Test: delete the comment and re-read the code; if it still makes sense, it stays deleted. What survives looks like a workaround for one specific device or vendor quirk, or a value that looks arbitrary and is not. Exception: configuration files (PHP config, .env.example, YAML manifests) — there a comment is the only documentation an option has, so comment freely. This governs shipped code only; PR bodies, register and journal entries are where you explain yourself at length.

Language

Operator websites are German. Search in German (Impressum, Kontakt, Netzbetreiber, Störung). Notes in the JSONL may be English.

Memory

memory/journal.md is the run journal — read it at the start of every run, append a dated entry at the end (batch processed, hit rate, oddities worth remembering).

Country facts

countries/de/info.yaml — what outreach is allowed to state about us
# Country facts — Germany. Single source for anything outreach needs to state
# about who we are (forms, signatures, follow-ups). Values verified against
# https://energiemarie.de/impressum on 2026-08-09 — update there first, then here.
brand: Energiemarie.de
legal_entity: Selectra SAS
registration: RCS Paris 499807147
manager: Aurian de Maupeou
address:
  street: rue Sébastien Mercier
  house_number: "66"
  postal_code: "75015"
  city: Paris
  country: Frankreich
impressum: https://energiemarie.de/impressum
outreach:
  contact_person: Stefanie Schäffer
  mailbox: [email protected]   # plus-addressing per operator: stefanie+<MaStR-Nr>@
  phone: "+33 1 86 26 41 26"
2026-09-08 05:30 run (netzbetreiber-replies, run 2026-09-08T05-30-00-c63de6) — scheduled run, 0 new messages, quiet pass netzbetreiber-replies

fetchmail.mjs → 0 new messages. fetchbrowser.mjs: only the standing SNB921080203146 (ew-rohmund.de) attempted, failed again with function 400 — 12th consecutive occurrence on this exact URL (logged every pass since 2026-09-04); still not escalating since brows…

wasserversorger-enrich run (scheduled, batch 45, tag 20260908-0530) wasserversorger-enrich

Ran buildenrichbatchexcl.mjs 45 20260908-0530: 746 pending, 0 pendingdomain. Split shard A (23) / shard B (22), same population-priority ordering as prior runs. Two parallel top-level subagents worked the shards; each of them further split its 20+ companies in…

wasserversorger-enrich run (scheduled, batch 45, tag 20260908-0030) wasserversorger-enrich

Ran buildenrichbatchexcl.mjs 45 20260908-0030: 791 pending, 0 pendingdomain this time (all already resolved), split shard A (23, all self-supplying small Bayern/Hessen/BW Gemeinden) / shard B (22, similar profile). Two parallel subagents researched contact fie…

2026-09-07 20:30 run (wasserversorger-enrich, scheduled task, tag 20260907-2030) wasserversorger-enrich

Batch of 45 (buildenrichbatchexcl.mjs 45 20260907-2030: 836 pending after the 6 standing excluded duplicate-mint pairs, 0 pendingdomain — the campaign's pendingdomain backlog is fully cleared, only the standing wv-de-7505 exclusion remains there). Split 23 (sh…

2026-09-07 17:30 run (netzbetreiber-replies, run 2026-09-07T17-30-00-c0b51a) — scheduled run, 4 messages, 3 full §14a extractions, 1 unresolvable reroute punted to human netzbetreiber-replies

fetchmail.mjs → 4 new messages, all matched. fetchbrowser.mjs: only SNB921080203146 (ew-rohmund.de) attempted, failed again with function 400 — 11th consecutive occurrence on this exact URL (logged every pass 2026-09-04 through now); still not escalating since…

Monthly report

Google Doc
Country OS — Germany
Updated
01/09/2026 08:11

2026-08 fragment

2026-07 fragment

Latest runs

all 369
WhenTaskWhat it reportedCost
08/09/2026 07:53netzbetreiber-repliesThis was a quiet pass: 0 new mail, 0 pending documents, nothing to triage. `fetch_browser.mjs` hit its standing `ew-rohmund.de` function-400 failure a…$0.42ok
08/09/2026 07:51wasserversorger-enrichJournal updated. The run is complete: batch of 45 water suppliers researched and merged, coverage stable, evidence trail intact, no forbidden actions…$37.58ok
08/09/2026 02:50wasserversorger-enrichJournal entry appended. Final summary for the report. Enriched 45 more German water suppliers (wasserversorger campaign): 39/45 got a full contact se…$14.66ok
07/09/2026 22:56wasserversorger-enrichRun complete. Enriched 45 water suppliers (23+22 shards, both validated and merged cleanly): 45/45 got address/phone/website, 41/45 email, 15/45 multi…$19.20ok
07/09/2026 19:34netzbetreiber-repliesThis run processed 4 messages: 3 full §14a extractions (Stadtwerke Konstanz, Talwerk GmbH/Stadtwerke Kaiserslautern, LokalWerke GmbH — all high-confid…$1.43ok
07/09/2026 18:10wasserversorger-enrichJournal updated. Final report: Enriched 45 German water suppliers (batch tag `20260907-1530`, 2 parallel subagents per shard cap) — phone/address/web…$34.70ok
07/09/2026 16:05wasserversorger-enrichBoth files clean. Run complete. **Outcome:** Enriched 45 more Wasserversorger (23+22 across two parallel research passes), bringing `enrichment.jsonl…$28.33ok
07/09/2026 12:54wasserversorger-enrichJournal entry appended. The run is complete. **Outcome:** Enriched 45 more German water suppliers (Wasserversorger) via 2 parallel subagents (23 + 22…$14.79ok
07/09/2026 10:30netzbetreiber-push-contentspushed 511 operator rows to contents (0 awaiting normalization)$0ok
07/09/2026 09:00netzbetreiber-send-dailydone: 0 sent, 0 failed → /app/countries/de/campaigns/netzbetreiber/sends.jsonl$0ok
07/09/2026 08:05netzbetreiber-repliesThis run processed 1 new message: Stadtwerke Norderstedt (SNB985965721965) replied with a link to their own Preisblatt, which I fetched and fully extr…$0.81ok
07/09/2026 08:02wasserversorger-enrichThis wasserversorger-enrich run completed cleanly: enriched 45 more water suppliers (2379→2424 of 3375 total, 976 pending), population coverage holds…$46.20ok
07/09/2026 03:07wasserversorger-enrichThese are historical batch files from past runs (consistent with the campaign's convention of keeping them); today's own batch files were already remo…$52.12ok
06/09/2026 22:53wasserversorger-enrichRun complete. Enriched 45 more water suppliers (2289 → 2334 distinct, `enrichment.jsonl` 2294 → 2339 lines), all verified as genuine active suppliers…$17.77ok
06/09/2026 19:32netzbetreiber-repliesJournal entry recorded. Final report: **netzbetreiber-replies run (2026-09-06 17:30) — quiet pass, no mail to triage.** - Fetch: 0 new inbox message…$0.52ok