Structure & orchestration¶
The automations are Python, but they don't run on anyone's laptop. Five external tools carry the system, and each has one job. This page is a usage guide: for every tool, what it does for us, where the settings that matter live, and how to change them. It's the page to open when something needs adjusting — a schedule, a key, a model.
flowchart LR
Cron["⏰ cron-job.org<br/>the trigger"] -->|pings| GH
GH["🐙 GitHub Actions<br/>the runtime"] -->|runs Python| Code
Code["🐍 The automations"] -->|reasoning| Claude["🤖 Claude Platform"]
Code -->|inbox| Google["📧 Google Cloud / Gmail"]
Dev["🛠️ Claude Code (VS Code)<br/>where it's built"] -.->|commits to| GH
A note on the callouts below
Boxes marked “Needs your detail” are where a console account only Benedikt/U2V can see — the exact project name, the cron job, the billing org. Everything else is verifiable from the repo.
GitHub — the runtime¶
Its job for us. GitHub has two jobs, and only two: it's the single place all the code is stored,
and — through GitHub Actions — it's what runs the automations on a schedule. There's no server;
a scheduled Action is the whole runtime. The live system always runs from the main branch, so once a
change is merged there it goes live on the next pass.
You read code on GitHub — you don't edit it here
The code side of GitHub is for browsing: open and read any file, but code is never changed on GitHub itself. Edits happen on your laptop in Claude Code and are pushed up. (The Actions and Settings tabs below are operational controls — they run and configure the system, they don't edit its code.)
What you'll see — the code view. The repo's front page is a list of u2v-* folders, one per
automation, each named for the job it does — u2v-dispatch,
u2v-dealflow, u2v-lp-share, and so on. Open any
folder and you can read the whole thing: the code under src/, the README.md (what it does and
how to run it) and the CLAUDE.md (the operating guide Claude Code reads). Start at the top-level
README.md, shown just under the folder list — it introduces the whole project and links to every
part. It's the best place to orient yourself before opening anything in Claude Code.
The Actions tab — run a pass now. The automations fire on a timer, but you don't have to wait for the
next one. Open the Actions tab, pick the workflow, and click Run workflow to trigger it on the
spot. The two schedules (defined in
.github/workflows/):
| Workflow | What it runs | Cadence |
|---|---|---|
dispatch.yml |
One pass over the klaus@u2v.vc inbox (the dispatcher) |
every 30 min |
dealflow-sample.yml |
The bi-monthly sample deck | 1st of the month, odd months only |
Their live timing, though, isn't set in the repo — an external cron pinger triggers these runs on schedule (GitHub's built-in scheduler proved unreliable). See The cron pinger below.
The Settings tab — people & secrets.
- Add a teammate. When someone new joins, add them under Settings → Collaborators so they get access to the repo.
- Secrets. The keys and tokens the automations need — Attio, Anthropic and Gmail, plus the scoped
keys for
lp-intakeandlp-tasks— live under Settings → Secrets and variables → Actions: encrypted, never in the code, injected as environment variables at run time.
Making changes? Sign in as Klaus first
The repo lives under the shared klaus-u2v GitHub account. To do anything that changes it —
merge to main, run a workflow, or edit settings or secrets — sign in to GitHub as that account
using the klaus@u2v.vc Google login (the same identity behind the inbox and the
Google Cloud project).
One last thing you'll notice while browsing: after each run the workflow commits a little state back to
the repo — the roster queue, the "last-featured" record — tagged [skip ci] so it doesn't re-trigger
itself. That's the system's memory, kept in git rather than a database (see
Design principles).
Claude Code (in VS Code) — where it's built¶
Its job for us. This whole system was written — and is maintained — in Claude Code, the agentic coding tool, running inside VS Code. It isn't part of the runtime (GitHub is); it's the workbench. It matters here because it's also how the next person works on the code.
Where the settings live. Every project carries a CLAUDE.md file — an operating guide Claude Code
reads automatically. The root CLAUDE.md describes the whole system; each u2v-*/CLAUDE.md describes
that one automation. These files are what make "ask Claude Code about X" throughout this site actually
work: the context is already written down.
How to use it. Never opened VS Code before? Start with the from-zero walkthrough — Getting set
up in VS Code — which takes you from downloading the editor to asking Claude Code
its first question about this repo. In short: open the repo folder, start a chat, and ask in plain
language — "explain how lp-share picks which deals are new," or "add a new workflow that does Y." It
has the CLAUDE.md context to answer and to make changes correctly, and adding a new automation is
deliberately cheap — the shape is identical every time (see Adding an automation).
The Claude Platform — the reasoning¶
Its job for us. Every judgment in the system — classifying an email, scoring a startup, researching an LP, ranking a shortlist — is a call to Anthropic's Claude models, all on a single account managed at the Claude platform console.
Who runs it, and when you'd open it. The organisation there is the Motu Ventures team, and Philipp is the admin. For our purposes there are only three reasons to ever go in:
| You want to… | Where in the console | Who can do it |
|---|---|---|
| Change the budget or rate limits the automations run under | Billing & limits | Philipp only |
| Add someone to the team — approve their pending request to join Motu Ventures | Organization settings | Philipp only |
| Copy the API key every automation runs on | API keys | Anyone with access |
That API key is the same value the repo stores as the ANTHROPIC_API_KEY Actions secret (see
GitHub, above) — so if Philipp rotates it in the console, that secret has to be
updated to match, or the automations stop authenticating on their next run.
Google Cloud — the Gmail connection¶
Its job for us. The system's front door is a single Gmail inbox, klaus@u2v.vc. Google Cloud's
only role is to grant the automations permission to use that inbox through the Gmail API — reading
each incoming email and sending the reply. Nothing else in the stack touches Google.
Why it's needed. Code can't simply "log in" to a Gmail account. Google requires an authorised
OAuth client to act on the account's behalf, plus a refresh token — a long-lived credential
that lets the system keep acting as klaus@u2v.vc on every scheduled run without a human ever signing
in. Issuing that client and that token is the entire reason a Google Cloud project exists here.
What we set up. One project holds the whole arrangement:
- Project
claude-automation-501109— owned by theklaus@u2v.vcGoogle account, with the Gmail API enabled. - An OAuth client named
u2v-dispatch local— authorised to read and send mail on the inbox. It supplies the repo'sGMAIL_CLIENT_ID/GMAIL_CLIENT_SECRET. - A one-time consent (via the helper below) minted the long-lived
GMAIL_REFRESH_TOKEN. Those three secrets are all the code needs — it talks to Gmail over plain REST and swaps the refresh token for a short-lived access token on each run.
How to find it — and re-authorise.
- Sign in to Google as
klaus@u2v.vc— the account that owns the project. - Open the project console: console.cloud.google.com → claude-automation-501109.
- Go to Google Auth Platform → Clients and open the
u2v-dispatch localclient — to view or rotate its ID and secret. - To mint a fresh refresh token — e.g. after rotating the client — run the dispatcher's helper locally
and complete the browser consent as
klaus@u2v.vc: Put the token it prints intoGMAIL_REFRESH_TOKEN(locally in.env, in CI as an Actions secret).
The cron pinger — the trigger¶
Its job for us. Something has to start each scheduled run, and GitHub's own built-in scheduler proved unreliable — runs got delayed or skipped. So an external service, cron-job.org, is the dependable clock: on a fixed schedule it calls the GitHub API to kick off a workflow.
How it's wired. Each job sends an authenticated request — carrying a scoped GitHub token — to a
workflow's workflow_dispatch endpoint
(api.github.com/repos/klaus-u2v/automations/actions/workflows/<file>/dispatches). It's the very same
"Run workflow" action you can click by hand in the Actions tab, just fired on a
timer instead.
The two jobs. Signed in, the dashboard shows exactly two:
| Job | Starts | Timing |
|---|---|---|
| U2V Dispatch | the dispatcher | every 30 min |
| U2V - Dealflow Sample Document Data Room | the sample deck | 1st of every month |
The sample-deck workflow then gates itself to odd months only, so one monthly ping gives a clean bi-monthly cadence — and it's started only by this pinger (no GitHub schedule), precisely so it can never double-fire and email two decks.
How to get in — and change the timing.
- Sign in to Google as
klaus@u2v.vc, then open console.cron-job.org/dashboard. - EDIT a job to change its cadence; HISTORY shows its recent runs (handy for confirming a ping actually fired). The timing lives here in the job — not in the repo.
If the pings stop, the automations go quiet
The entire live cadence hangs on this one account and its scoped GitHub token. If the token expires or a job gets paused, the runs simply stop — with no error anywhere in the repo. So if the automations ever go mysteriously idle, this dashboard is the first place to look.
Adding a new automation¶
Because every project shares the same skeleton, the mechanics of adding one are deliberately cheap —
and the repo's root CLAUDE.md now spells out the exact checklist Claude Code follows to wire one up
correctly (the --json contract, the dispatcher registration, the CI venv step, scoped keys). So the
code is rarely where a new automation succeeds or fails.
The hard part — the part only you can do — is being clear about what you want to build.
Clarity of intent is the real work¶
Claude Code is genuinely excellent at building. What it cannot do is guess the automation you have in your head — and the quality of what you get out is set almost entirely by the precision of what you put in. So the recommendation is blunt: do the thinking first. Before you open the editor, get clear on
- What exactly it should do — the one job, start to finish: its trigger (an email? a schedule?), what it reads or writes in Attio, and the result a person gets back.
- How it should get there — the rough shape of the steps, and the judgment calls: what's plain deterministic code versus where a model is genuinely needed (see the model does judgment, not plumbing).
- What "done well" means — the edge cases it must handle, what it should refuse to guess rather than get wrong, and what it must never overwrite.
You don't need to work out the implementation — that's Claude Code's job. You need the vision, sharp enough to say out loud.
Then build it with Plan mode¶
Once you can state that vision clearly, hand it over in Plan mode (see
Getting set up in VS Code). Describe what you want — the more precise, the
better — and let Claude Code draft a plan before it writes any code. Plan mode is a real thinking
partner: it will pressure-test your idea, tell you honestly whether an approach holds together, and
raise things you hadn't considered. But it works with your vision, not in place of it — the clearer
you are, the better the plan. A good move is to point it at an existing automation to model:
"build this like u2v-lp-tasks, but for X." It will replicate the backbone, following the checklist
in CLAUDE.md. Read the plan, refine it, and only then let it build.
Think clearly about what you want to achieve and how to get there, then formulate that vision cleanly to Claude Code in Plan mode — and it will make it real.
What actually gets wired¶
For reference, this is the "definition of done" Claude Code works through for a routed workflow
(all of it lives, in full, in the root CLAUDE.md):
- Scaffold a new
u2v-<name>/with the standard skeleton, modelled on the nearest sibling. - A CLI honouring the
--jsonenvelope. - Register it in
u2v-dispatch/workflows.yaml— the classifier learns the new intent from its description; no dispatcher code change for a normal data-shaped workflow. - Wire CI — add its venv to the
dispatch.ymlbuild list (and any scoped secrets).
An autonomous one (like the sample deck) skips the dispatcher and ships its own scheduled Action instead.
Go deeper
Want the precise, current wiring? Open the repo in Claude Code
and ask "walk me through dispatch.yml step by step," or "what exactly does the gmail-auth
command do?"