The agent wakes on a schedule, on a webhook, or when mail arrives, reads your systems, does the work, and reports back. It runs in your Google Cloud project, on your jobs, billed to your own Claude subscription. This page is every step from an empty project to a first run — about an afternoon, most of it waiting for Google.
# the whole set-up, condensed to the command for each step
npx @meffecta/agent steps
npx @meffecta/agent help
Nothing about your business lives in the engine.
ghcr.io/meffecta/agent — the job runner, the skills that reach Gmail,
Grafana, PostHog, Google Ads and the rest, and the operator scripts. Public, and it
names no company. You deploy it; you never fork it.
Your jobs, your context, your settings. Every run clones it fresh, so editing a job's prompt is live on the next run — no build, no deploy.
The whole set-up below is: make a place for the engine to run, give it credentials, point it at your content repo, and tell it when to wake up.
On the machine you will operate from — macOS or Linux.
gcloud auth login), on a Google account that may create projectsnpm i -g @meffecta/agent # or use npx, which needs no install npm i -g @anthropic-ai/claude-code # used once, for the token in step 4 meffecta-agent version # names the engine build this version deploys
Pin the version you install. Each release of the tool deploys the engine image published alongside it, so upgrading the tool is how you move to a new engine — deliberately, rather than by surprise.
Nine steps. Each one is checkable before you go on.
Give the agent a project of its own, separate from any product project it will read: everything the agent runs as can read every password stored in this project, and your mail tokens should not sit where another system's machinery can reach them.
npx @meffecta/agent create-project
acme-agent-506513). The ID, not the display name, is what every later command needs.It lists the accounts you can use, marks closed ones as unselectable, links your choice, and then checks the project really is billed — because linking can report success and still leave it unbilled.
npx @meffecta/agent link-billing --project <PROJECT_ID>
A private GitHub repo holding everything about this deployment. Create it, clone it, and run init inside — every command from here on runs from this directory, which is what says which deployment you mean.
npx @meffecta/agent init # writes deployment.env and scaffolds the repo
deployment.env # which GCP project and service your deployment is SYSTEM.md # who the agent serves, its businesses, its tone systems/ # one file per system it can reach, and the variable for each jobs/ # one .md per job: a few settings, then the prompt worlds/ # optional — what the agent should know about your business skills/ # optional — skills your deployment owns or overrides
worlds/ is always a folder, and each thing inside it is one world — a business, product or brand the agent works on. A world holds what would otherwise be repeated in every job: who you sell to, what you may claim, who the competitors are. One world is either a single file (worlds/acme.md) or a folder of them (worlds/acme/) once there is more than a page of it. Most deployments have exactly one. Skip the whole thing to begin with; nothing depends on it.
deployment.env is committed — none of it is secret, and a clone of the repo is then everything an operator needs:
PROJECT=acme-agent-506513 # the project ID from step 1
SERVICE=acme-agent
ARTIFACT_REPO=acme-agent-images
REGION=europe-west1
Three things, and only the first two are required.
claude setup-token # → CLAUDE_CODE_OAUTH_TOKEN, pasted in step 6
Safe to run as many times as you like — re-run it after any change. It switches on the Google APIs, creates the registry the engine image is served from, the login the agent itself acts as, a bucket for its memory, a write-once bucket for the audit trail (kept a year), and the empty service the engine will run in.
If you would rather see it before it does anything, ask it first. This changes nothing at all — it just prints everything it would create and every permission it would grant, in your project:
npx @meffecta/agent setup-infra --dry-run
Then, for real:
npx @meffecta/agent setup-infra
deployment.env — if not, you are in the wrong directory.Secrets go into Google's Secret Manager and are connected to the service in one step; the value is never shown on screen, and never saved in your command history. Re-running one rotates it.
npx @meffecta/agent set-secret AGENT_API_SECRET --random # generated for you npx @meffecta/agent set-secret CLAUDE_CODE_OAUTH_TOKEN # prompts, hidden npx @meffecta/agent set-secret GITHUB_TOKEN
Non-secret settings go through set-env. The service will not boot without GIT_REPO_URL:
npx @meffecta/agent set-env GIT_REPO_URL=https://github.com/<owner>/<repo>.git
That is everything the engine needs. Anything else — Gmail, analytics, logs, a CRM — is one credential each, added whenever you want the ability, not now.
Rolls out the engine build this version of the tool was published with, and sets the service's size and scaling from deployment.env — so a setting changed by hand in the console cannot quietly survive a deploy. --tag <other> goes to a different build, which is also how you roll back.
npx @meffecta/agent deploy --dry-run # see the target first
npx @meffecta/agent deploy
It then creates the triggers, because the service sleeps when nothing is happening and is only awake while answering a request — so nothing inside it can run on a timer of its own. One Cloud Scheduler job per cron: in your jobs, and a housekeeping sweep. It can only do this after the engine is running, since the running engine is the only thing that knows which jobs exist.
<service>-sweep, and meffecta-agent triggers agrees.Every later rollout re-syncs them, so a changed cron: needs nothing extra. To re-sync without a rollout — the only time you need it on its own — run npx @meffecta/agent sync-triggers.
npx @meffecta/agent status npx @meffecta/agent jobs npx @meffecta/agent doctor
Seeing your jobs listed is what proves the service could read your content repo. An empty list means GIT_REPO_URL is wrong or GITHUB_TOKEN cannot clone it.
To see what all of this actually created inside Google Cloud — and what each piece is for, in plain words — there is one more:
npx @meffecta/agent resources
It lists everything, says which parts cost anything, and gives you a link straight into the Google Cloud console for each one. Nothing you have to remember the name of.
Then test every connection you have set up, from inside the deployment:
npx @meffecta/agent verify-credentials
skip only means you have not set that one up yet.The same thing has a web page, for anyone who would rather not use a terminal: open /ask on the service URL that status printed. Any username, the secret as the password.
npx @meffecta/agent run hello npx @meffecta/agent logs --limit 50
Everything about your deployment. Nothing about the engine.
acme-agent/ deployment.env # which GCP project and service your deployment is SYSTEM.md # the rules every job gets, before its own instructions jobs/ # one file per job morning-brief.md weekly-review.md systems/ # one file per system it can reach gmail.md google-analytics.md worlds/ # optional — what it should know about the business acme.md skills/ # optional — procedures of your own, or overrides accounting/SKILL.md
| deployment.env | Which GCP project, service, region and image repository this is. Committed on purpose — none of it is secret, so a clone of the repo is everything the next operator needs. |
| SYSTEM.md | Rules, not facts. It goes in front of every job: who the agent serves, how it should write, what it must never do. The engine adds its own baseline after yours, so the safety rules you cannot switch off stay on. |
| jobs/*.md | A few settings, then a page of plain-language instructions — below. |
| systems/*.md | The register. One file per system, naming the skill that reaches it, the variables holding its credential, what access is allowed, and the cheapest read that proves it works. A system with no file here is a system the agent does not have — the credential can be perfectly valid and still no job will ever use it. |
| worlds/ | One world per business, product or brand — each either a single file (worlds/acme.md) or a folder of them. Facts that outlive any one job, and that travel with the agent when a job runs inside one of your other repos. |
| skills/ | A procedure of your own. A folder named after one of the built-in skills replaces it — the folder name is what decides, so renaming one quietly stops it overriding anything. |
| On push | Prompts, run settings, SYSTEM.md, systems/, worlds/, skills/. Live on the next run — there is nothing to build and nothing to deploy. |
| On deploy | Whether a job exists, and when it fires: a new job file, a renamed one, or a changed cron:, webhook: or inbox:. These are read once when the service starts, so it has to restart to see them. |
Renaming a job file makes a new job. Its memory is kept under its name, so the old name keeps the history and the new one starts blank — worth doing deliberately rather than while tidying up.
A page of plain-language instructions. Teaching it something new is editing that page.
jobs/hello.md
---
name: hello
cron: "0 7 * * 1-5"
---
Say good morning and list today's date. Send it by email to <person> using the
send-email skill. If email is unavailable, return the text as your result.
Settings a job can carry: cron, webhook, inbox,
repo, systemMd, model, effort,
allowedTools, timeoutSeconds, disabled. A job
with no name: takes its filename.
deploy, which restarts the service so the new cron: is registered.disabled: true is the kill switch, effective on push.Every prompt, result and full transcript lands in the audit bucket. Add jobs one at a time and read the first few runs of each.
Describe what you want in a sentence. The agent writes the page, because it is the one that has to read it:
npx @meffecta/agent create-job "a marketing report every Wednesday at 2pm"
It thinks about this on the deployment rather than on your laptop, which is the point — from there it can see the jobs you already have, the systems you have connected, and what it is actually able to do. So it writes something that fits, names the right systems, and tells you if you have asked for something it cannot reach yet.
You get a file — jobs/<name>.md — and nothing else happens. It is not
committed, not deployed, not scheduled. Read it before you keep it: this is the page your
agent will act on, and it is meant to be edited. Change the wording, tighten what it should
produce, fix the day.
npx @meffecta/agent check-jobs — it re-checks every job page here, so a schedule you edited by hand cannot quietly stop working.Add --dry-run to see it without saving anything.
Ongoing work rather than set-up — one credential each, whenever you want the ability.
npx @meffecta/agent connect # what can be connected npx @meffecta/agent connect gmail # what to do, in order, with the commands
Each walkthrough names what the agent gains, what you have to create on the other side,
and the exact set-secret / set-env to finish it:
gmail, outlook, ga4 (with Search Console and Google Ads),
grafana, posthog, serper, hubspot, kleer,
mongodb, cloudflare, and inbox — triggering a job by emailing it.
Google Analytics, Search Console and Google Ads need no token at all: they authenticate as the agent's own login instead, so you invite that as a viewer on each property of minting anything. Nothing breaks while you wait — a job that cannot reach a system says so and carries on.
Run from the content repo. Every command takes --help.
| doctor | The one to run when something feels wrong — it judges rather than describes, and every finding carries the command that fixes it |
| status | Revision, runtime shape, triggers, and what is in the queue right now |
| jobs | What the service has registered, and what triggers each |
| env / secrets | Every setting, and what is in Secret Manager — values are never printed |
| triggers | The Cloud Scheduler jobs and the task queue that drive it |
| logs --limit 100 | Recent service logs |
| run <job> | Trigger one job now, or --in <seconds> |
| ask "…" | Ask it something as a one-off run, with the same skills and context a job gets |
| create-job "…" | Have it write a new job page from a description, for you to read and edit |
| check-jobs | Re-check the job pages here — worth running after you edit one |
| resources | Everything the set-up built in Google Cloud, what each part is for, and a link to each |
| deploy | Move to a new engine — npm i -g @meffecta/agent@latest first, since the pair travels together |
doctor exists for these, and fails with an error when something is genuinely wrong, so you can run it on a schedule: