Business automation — Python, Rust, TypeScript. Bulgaria, working with clients across the EU, UK and US.
I build the unglamorous tools businesses run every day: data reconciliation, catalogue and deliverability audits, webhook-to-CRM integrations, and the monitoring that tells you an automation stopped working before a customer does.
Everything below is open source and runs on a clean machine with one command. Each repository has its own tests in CI, documents what it deliberately does not do, and where a README claims a number, the script that produced it is in the repository.
How many sites publish an llms.txt has been counted several times this year. This is the next question: of the 123 files found among the 1,500 most visited sites, 13 belong to sites whose robots.txt bans, by name, a crawler that would read them — and 13.5% of the files point at least one link at a page that is gone. A map with dead streets is worse than no map.
A security.txt tells a researcher where to report a hole in your site, and RFC 9116 makes its Expires field mandatory — an expired file is, in the words of the specification, as good as no file. Of the 158 such files among the 500 most visited sites, 92 carry no Expires at all and 6 have expired: 62% are not valid. Nothing warns when that happens.
Google and Shopify published the Universal Commerce Protocol so an agent can read a shop and buy from it. Nobody had published a count of how many shops actually speak it, so I measured it: 98.9% publish a valid profile, every one of them on the current release, none with a blocker. The only thing they differ on is whether an agent may sign the shopper into their own account — and 47.5% do not allow it, which turns a returning customer into an anonymous visitor.
Diffs two CSV exports by key and reports what actually changed. Two million rows in 2.8 seconds, a per-column breakdown with counted transitions, and number/null normalisation — so a migration report reads as 9 809 real changes instead of 995 000 rows of timestamp noise.
Offline check of what leaves with a file before you send it: tracked changes with the deleted text still readable, review comments, hidden worksheets, PDF attachments, GPS coordinates in photos, validated card and IBAN numbers.
Perceptual-hash duplicate finder. Complete-linkage grouping, so unrelated pictures never chain together through a path of small steps — and it writes a delete script for you to read instead of deleting anything itself.
Crawls a site and reports the links that are genuinely broken, keeping bot protection and slow third parties out of the "broken" column — which is why the report still gets read after the second run.
Record the webhooks a provider sends you once, then replay them at your own code as often as you need — re-signed for Meta, GitHub, Shopify or Stripe, so the receiver runs its real verification instead of having it switched off for the debugging session.
A site publishes a dozen small files at its root — security.txt, robots.txt, llms.txt, assetlinks.json, mta-sts.txt — each checked by a different tool or by nobody. This reads all of them in one run and says which are missing, malformed, or quietly expired. RFC 9116 gives security.txt an Expires date; past it, the file is no longer valid, and almost nobody notices.
Google and Shopify's Universal Commerce Protocol lets AI agents shop: every business publishes a profile at /.well-known/ucp and agents read it to decide what they can do. The failure mode is silence — offer checkout without declaring a searchable catalogue and no agent ever surfaces your products. This reads the profile the way an agent does.
Since 11 September 2026 a manufacturer placing a product on the EU market has 24 hours to notify ENISA of an actively exploited vulnerability in it. Finding vulnerabilities is not the hard part — any scanner hands you a hundred. This says which of them starts the statutory clock, and drafts the Article 14 notification for the ones that do.
Records the shape of a JSON API and reports when it changes: removed fields, changed types, values that can now be null. Exits non-zero in CI, so a partner's silent rename stops being something you find out about two weeks later.
Matches a bank statement against open invoices in five passes — references, part payments, batch transfers, instalments — and reports only what does not add up. Standard library only.
WhatsApp Business Cloud webhooks into a CRM: signature verification, instant acknowledgement plus queue, de-duplication, conversations logged against both the contact and the company, the 24-hour window, token refresh.
Finds why a domain's mail lands in spam: SPF lookup limit, duplicated records, revoked DKIM keys, DMARC stuck at p=none, missing MTA-STS. DNS only — no access to the mailbox needed, batch mode for client lists.
Answers a web enquiry in under a second: scores it, writes a personal reply, offers real call slots, escalates the hot ones and files the spam. Rules live in YAML, no API keys.
curl -sSL https://github.com/dkautomation23/csvdiff/releases/latest/download/csvdiff-v1.0.0-x86_64-unknown-linux-gnu.tar.gz | tar xz ./csvdiff-v1.0.0-x86_64-unknown-linux-gnu/csvdiff before.csv after.csv --key customer_id --ignore updated_at
Every release carries a binary for Linux, macOS (Apple silicon) and Windows, each built and tested on the platform it targets rather than cross-compiled.
A workflow that stopped running, an API that changed shape, a feed half-empty for a fortnight. Monitoring that names the failure, not a dashboard nobody opens.
Webhooks into a CRM, a bank statement against invoices, a catalogue against a supplier feed. Signature verification, de-duplication, retries and the 3am cases.
Migration checks, reconciliation, audits of a catalogue, a domain's mail or a site's crawlability — with the numbers reproducible rather than asserted.
An automation someone else built and left. I will read it and tell you honestly whether it is worth repairing or worth replacing.
Tell me what breaks today and what it costs you: [email protected]. You get back an approach and a number, or an honest “this is not my job” and who to ask instead.