Meffecta Agent
Getting started

An AI colleague,
in your own cloud.

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

Two halves, and why the steps look like this

Nothing about your business lives in the engine.

The engine

A container image

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 content repo

A private Git repo

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.

Before you begin

On the machine you will operate from — macOS or Linux.

npm 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.

The set-up, in order

Nine steps. Each one is checkable before you go on.

01

Create a GCP project

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
Note the project ID it prints. Project IDs are globally unique, so a plain name is often taken and you end up with a suffixed one (acme-agent-506513). The ID, not the display name, is what every later command needs.
02

Link a billing account

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>
It reports billingEnabled: true.
03

Create the content repo

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
The repo is pushed to GitHub, and you are inside it.
04

Mint the credentials

Three things, and only the first two are required.

claude setup-token    # → CLAUDE_CODE_OAUTH_TOKEN, pasted in step 6
  • CLAUDE_CODE_OAUTH_TOKEN — your deployment bills its own runs
  • GITHUB_TOKEN — a fine-grained PAT with contents: read on the content repo (the service cannot start without it), plus write on any repo whose jobs open pull requests
  • A mailbox token, only if the agent reads or sends mail — see giving it access
05

Provision the infrastructure

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
The banner names the project from your deployment.env — if not, you are in the wrong directory.
06

Wire up the configuration

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.

07

Deploy the engine, and its triggers

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.

It reports one trigger per cron job, plus <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.

08

Verify

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
Each one reports ok or skip, and none reports FAIL — 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.

09

The first real run

npx @meffecta/agent run hello
npx @meffecta/agent logs --limit 50
Read what it produced before letting the cron take over.

What lives in your content repo

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.envWhich 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.mdRules, 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/*.mdA few settings, then a page of plain-language instructions — below.
systems/*.mdThe 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.

What is effective when

On pushPrompts, run settings, SYSTEM.md, systems/, worlds/, skills/. Live on the next run — there is nothing to build and nothing to deploy.
On deployWhether 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.

What a job is

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.

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.

Let it write one for you

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.

Then 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.

Giving it access to a system

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.

Day to day

Run from the content repo. Every command takes --help.

doctorThe one to run when something feels wrong — it judges rather than describes, and every finding carries the command that fixes it
statusRevision, runtime shape, triggers, and what is in the queue right now
jobsWhat the service has registered, and what triggers each
env / secretsEvery setting, and what is in Secret Manager — values are never printed
triggersThe Cloud Scheduler jobs and the task queue that drive it
logs --limit 100Recent 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-jobsRe-check the job pages here — worth running after you edit one
resourcesEverything the set-up built in Google Cloud, what each part is for, and a link to each
deployMove to a new engine — npm i -g @meffecta/agent@latest first, since the pair travels together

The failures that produce no error anywhere

doctor exists for these, and fails with an error when something is genuinely wrong, so you can run it on a schedule: