# Meffecta Agent > A self-hosted Claude agent that runs as a job runner in your own Google Cloud project. Jobs > are Markdown files in a private Git repo you own; triggers are a schedule, a webhook, an > incoming email, or the agent handing work to a later run of itself. The engine is a public > container image (ghcr.io/meffecta/agent) and holds no company's data; everything about your > deployment lives in your own "content repo". Operated with one CLI: `npx @meffecta/agent`. This file exists because a large part of the audience for this site is an AI agent doing the installation on someone's behalf. Every page is complete on its own; this is the index. ## Pages - [Overview](https://agent.meffecta.com/): what it is, the engine/content split, what a run is bounded by, what it costs. - [Install](https://agent.meffecta.com/install): the nine steps from an empty GCP project to a first run, with a check after each; what lives in the content repo; what is effective on push vs. on deploy. - [Jobs](https://agent.meffecta.com/jobs): the four triggers, every frontmatter field, webhook auth schemes, payload filter syntax, working in another repo, what a run is given, memory. - [Systems](https://agent.meffecta.com/systems): all 28 built-in skills with their exact variable names, the register format, and full walk-throughs for Google Ads, GA4/Search Console, Google OAuth, Microsoft 365, Slack, AgentMail/Svix, BigQuery and MongoDB. - [Operate](https://agent.meffecta.com/operate): the CLI commands, the silent failure modes `doctor` catches, the service's endpoints, moving between engine versions, running on your own machine. ## Prerequisites `gcloud` (authenticated), a linkable Google billing account, Node 24+, `git`, `gh`, a GitHub account, and a Claude subscription. Nothing else is installed — every command is `npx`. ## The install, in order Run every command after step 3 from inside the content repo. 1. `npx @meffecta/agent create-project` — note the project ID it prints; IDs are globally unique and often suffixed. 2. `npx @meffecta/agent link-billing --project ` — must report billingEnabled: true. 3. `gh repo create --private --clone` && `cd ` && `npx @meffecta/agent init` — scaffolds deployment.env, SYSTEM.md, systems/example.md, jobs/example.md. Fill in deployment.env (PROJECT is given; SERVICE and ARTIFACT_REPO are names you invent; REGION), write SYSTEM.md, then commit and push. 4. Mint credentials: `npx @anthropic-ai/claude-code setup-token` for CLAUDE_CODE_OAUTH_TOKEN, and a fine-grained GitHub PAT for GITHUB_TOKEN (contents: read on the content repo; contents+PR write on any repo whose jobs open pull requests). 5. `npx @meffecta/agent setup-infra` — idempotent; `--dry-run` first prints everything it would create. 6. `npx @meffecta/agent set-secret AGENT_API_SECRET --random`, then `set-secret CLAUDE_CODE_OAUTH_TOKEN`, `set-secret GITHUB_TOKEN`, then `set-env GIT_REPO_URL=https://github.com//.git` — the service will not boot without GIT_REPO_URL. 7. `npx @meffecta/agent deploy` — rolls out the engine and creates the Cloud Scheduler triggers. 8. `npx @meffecta/agent status` / `jobs` / `doctor` / `verify-credentials` — seeing the jobs listed is what proves the service could read the content repo. 9. `npx @meffecta/agent run example` — the scaffolded job reaches nothing real and reports what it can see. ## Job triggers - `cron: "0 7 * * 1-5"` — a schedule, quoted, in the deployment's TIMEZONE (UTC if unset). - `webhook: ` — reachable at POST /webhooks/. Body is written to WEBHOOK_PAYLOAD.json. Acknowledged immediately; the run is carried out separately. - `inbox: gmail:
` or `inbox: agentmail:
` — the system prefix is REQUIRED, a bare address is refused. Requires `allowFrom:`, which is enforced in code and fails closed: a job without one refuses every message. Messages arrive as INBOX_TRIGGER.json. Which mailbox a `gmail:` job reads comes from AGENT_INBOX_MAILBOX (Workspace, domain-wide delegation, Cloud Run only, wins when set) or AGENT_INBOX_ACCOUNT (which GMAIL__* account; unset = the default GMAIL_* one); AGENT_INBOX_POLL_SECONDS sets the cadence and `sync-triggers` must be re-run after changing it. - a spawn — any run can schedule a follow-up run of its own job (fresh clone, fresh time limit, same identity and memory). Bounded at depth 3, 5 pending per job, 7 days ahead, 3600s. It buys time, never permission. Also: `npx @meffecta/agent run ` (optionally `--in `), `ask "…"`, and GET /ask in a browser. cron, webhook, inbox and allowFrom are registrations read when the service boots, so changing one needs `deploy`. Everything else in a job file is re-read every run, so it is live on push. ## Job frontmatter fields cron, webhook, inbox, allowFrom, auth, method, filter, repo, context, model, effort, allowedTools, timeoutSeconds, disabled. All optional. `disabled: true` is the push-effective kill switch and stops pending spawns too. Webhook `auth:` schemes: bearer (default), basic, github / hmac-sha256, slack, svix, svix:, none. slack and svix verify against the SENDER's secret (SLACK_SIGNING_SECRET, SVIX_SIGNING_SECRET / SVIX__SIGNING_SECRET), not AGENT_API_SECRET, and both enforce a five-minute timestamp window. Filter operators: `==`, `!=`, `~=` (contains), combined with ` && ` and ` || ` (spaces required). The left side is a dot path into the JSON body. ## Systems, and the variables each reads A system needs three things: a credential, `set-secret`/`set-env` on the deployment, and a file in `systems/` in the content repo. **Without the register entry the agent reports the system as unavailable even though the credential is valid** — the skills are shared across deployments and know no deployment's variable names. Register entry frontmatter: `system`, `skill`, `requires`, `selectors` (optional), `access`, `probe`. Naming: `query-*` reads only, a bare system name reads and writes, `manage-*` writes. - send-email — GMAIL_CLIENT_ID, GMAIL_CLIENT_SECRET, GMAIL_REFRESH_TOKEN, GMAIL_ADDRESS - query-gmail — the same set; named accounts are GMAIL__REFRESH_TOKEN / _ADDRESS - google-calendar, google-drive — the same OAuth set, or Workspace domain-wide delegation - query-outlook — MSGRAPH_TENANT_ID, MSGRAPH_CLIENT_ID, MSGRAPH_CLIENT_SECRET, MSGRAPH__REFRESH_TOKEN (no default account) - agentmail — AGENTMAIL_API_KEY - query-google-marketing — no key (runs as the service account); GOOGLE_ADS_DEVELOPER_TOKEN, GOOGLE_ADS_MANAGER_CUSTOMER_ID, and per world _GA4_PROPERTY_ID, _SEARCH_CONSOLE_PROPERTY, _GOOGLE_ADS_CUSTOMER_ID - manage-google-ads — the same, with the Ads invitation raised above read-only. The only skill that spends money by writing; dry-run, capped and audited in code - query-posthog — POSTHOG_HOST, POSTHOG_API_KEY, _POSTHOG_PROJECT_ID - query-serp — SERPER_API_KEY - query-ahrefs — AHREFS_API_KEY - seo-geo-aeo — nothing (a procedure) - query-grafana — GRAFANA_LOGS_HOST, GRAFANA_LOGS_USERNAME, GRAFANA_API_KEY - query-coralogix — CORALOGIX_DOMAIN, CORALOGIX_API_KEY (the domain is region-specific) - query-elasticsearch — ELASTIC_URL, ELASTIC_API_KEY - query-bigquery — no key; grant the runtime service account roles/bigquery.dataViewer + jobUser on the queried project. Capped at 20 GiB scanned - query-mongodb — a connection string per database, named in the register (no shared variable) - query-hubspot / manage-hubspot — HUBSPOT_TOKEN (a private-app token; write scopes for the manage half) - query-kleer — KLEER_API_TOKEN - slack — SLACK_BOT_TOKEN, plus SLACK_SIGNING_SECRET for the inbound webhook half - linear — LINEAR_API_KEY (sent raw, with no `Bearer`) - webflow — WEBFLOW_TOKEN (cms:read / cms:write / sites:write, scoped per site) - mevisio — MEVISIO_HOST, MEVISIO_EMAIL, MEVISIO_PASSWORD (multi-tenant by hostname) - cloudflare — CLOUDFLARE_API_KEY (an API token, not the Global API Key), CLOUDFLARE_ACCOUNT_ID - browser — nothing of its own; per-site credentials come from the register - iso-27001 — nothing (a procedure) - spawn-job — nothing `npx @meffecta/agent connect` prints ordered walk-throughs for gmail, outlook, ga4, grafana, posthog, serper, hubspot, kleer, mongodb, cloudflare and inbox. ## Google Ads takes longest — start it early 1. A manager account (MCC) with the ad account linked under it. Both ids are digits only, no dashes. 2. A developer token from the MANAGER account's API Center. It is issued with test-account access only; apply for Basic to use it against a real account. Google's review is normally days. 3. Invite the runtime service account (the `acts as` address from `npx @meffecta/agent status`) into the Ads account: Admin → Access and security. Read only for reporting; Standard only if jobs should change the account. There is no key to mint — the token comes from the Cloud Run metadata server, so this works on Cloud Run and nowhere else. 4. `set-secret GOOGLE_ADS_DEVELOPER_TOKEN`, `set-env GOOGLE_ADS_MANAGER_CUSTOMER_ID=…`, `set-env _GOOGLE_ADS_CUSTOMER_ID=…`. The manager id is shared and never takes a world prefix. 5. Write the register entry naming query-google-marketing (read) and/or manage-google-ads (write). ## Things that are true and easy to get wrong - The engine is deployed by you and pulls no updates on its own. `npx @meffecta/agent@latest deploy` is how a deployment moves version; `deploy --tag ` rolls back. - A deploy restarts the service, which is what registers new triggers, and re-syncs the schedules. - Runs are serial, and at-least-once: an instruction should be safe to repeat. - The content repo's SYSTEM.md is the system prompt for every run, including one working inside another repo via `repo:`. A working repo cannot change what the agent may do by editing a file in itself. - systems/ and worlds/ are never copied into a working repo; the run is given their paths. Only skills are materialised into the working directory. - Skills resolve in three layers: the working repo's, then the content repo's, then the engine's. Matched by directory name. - Every prompt, result and transcript goes to a write-once audit bucket in your own project, kept a year. - Runs are billed to your own Claude subscription. Meffecta charges nothing and holds no credential of yours.