Building a GTM machine in public: the journey so far, and what comes next
How I build an outbound engine in public: what it does, what broke, and what I'm changing every two weeks.

I'm building an outbound system that runs itself, and I want to show how it gets built: the decisions, the mistakes, and what changes week to week. This is the first post in that series. It covers where the project started, what it does today, and what I'll publish from here on.
Where it started
The idea came from a simple observation. When a company posts a job for a sales role, it's usually about to grow, and a growing team has a real problem: how fast does a new hire start closing on their own? Job postings are public, so the signal is free. The hard part is everything after that: finding the right person, judging whether the fit is real, writing a mail that doesn't read like a template, sending it at a sane pace, and keeping the whole thing running without babysitting.
I'd been doing that by hand, and by hand it doesn't scale. So I started building a machine for it.
What it does today
The GTM Engine runs one pass every ten minutes, in a fixed order. It takes in replies and link clicks first, so anyone who has already answered never gets a follow-up. It creates due follow-ups, refills its queue when stock runs low, has a review step check each draft, sends within the limits the rules allow, and writes a daily report.
Those limits are code, not a checklist. Mails go out only in the send window. Each mailbox has a daily cap that grows over a warm-up period. Once a mailbox has sent 20 mails, a bounce rate over 3 percent stops it automatically, and a contact who unsubscribes is blocked by address and domain. Free-mail domains such as gmail.com block only the address. The autopilot doesn't get exceptions. It presses the same button a person would.
The part I'm most interested in is what happens when things go wrong:
- The process restarts itself. On Windows, a scheduled task relaunches the engine every minute if it dies, without starting a second copy.
- Failed sends retry, but only when a retry makes sense. Temporary server errors go back into the queue, up to five attempts. Permanent errors are logged and stop there.
- Drafts get repaired before they're held back. Simple rule checks fix salutations, dashes and job-ad noise that leaked into a mail. A second model reviews what's left. Anything that can't be fixed is held, not sent.
- A watcher checks the watcher. A read-only heartbeat script raises an alarm when approved mails are due but nothing has gone out for an hour inside the sending window, unless the engine itself says it's waiting for a daily cap or a closed window.
I wouldn't call it self-optimising. It detects that it's stuck, and it fixes a narrow set of mechanical faults. Deciding what to do about a strategy that isn't working is still my job.
Lessons from building it
Most of the lessons so far are about boring things.
Make automation boring. A fixed order of steps, with every limit enforced in code, is easier to trust than anything clever.
Write down why each failure is retried or not. The log line that explains a decision is worth more than the decision itself.
Put the watcher outside the thing it watches. The heartbeat is read-only. It can tell me something is wrong, but it can't change anything.
Test the tests. My own test runner once chained the test scripts with &&. A noisy shutdown on Windows silently stopped every test after the first abort, and nobody noticed for a while. Each test now runs in its own process, and an abort during cleanup is reported as such.
Keep the person in the loop where a mistake is expensive. Drafts can be approved, changed or discarded. Sending without approval is a setting, not a default.
Going open source, step by step
I'm preparing the engine to be shared as open source under the MIT license. It will include a demo mode with invented data, so you can see the whole thing running without touching a real mailbox or a real contact. I'll share the link when the code is ready, and I'll check it for personal data before release.
When it's out, I want the setup to be easy for others to try. The user interface is still in German, and an English version would be one of the most useful contributions.
What's next: a post every two weeks
From here on I'll publish on GTM Daily every two weeks. Each post will cover three things:
- What changed in the repo. Features, fixes, and the things that broke, with the reasons.
- What I learned. The decisions that held up and the ones I had to reverse.
- What I'm working on next. So you can tell me if I'm about to make a mistake.
I'm not going to publish my operating numbers yet. The sample is too small to mean anything, and I'd rather wait until the numbers are worth reading than publish them with caveats. When that changes, I'll say so in one of these posts, and I'll explain how I measured.
If you're building something similar, or you think I'm building the wrong thing, I'd like to hear it. The next post comes in two weeks.