@meffecta/agent 1.0.7 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +77 -110
- package/engine.json +2 -2
- package/lib/create-job.js +1 -1
- package/lib/verify-credentials.js +2 -2
- package/package.json +2 -1
- package/scripts/verify-credentials.mjs +37 -6
package/README.md
CHANGED
|
@@ -1,142 +1,109 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Meffecta Agent
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
An AI colleague that runs in **your own Google Cloud**, on **your own jobs**, against your
|
|
4
|
+
own systems. It wakes on a schedule, a webhook, or an email, does a piece of real work, and
|
|
5
|
+
reports back — then goes back to sleep costing nothing.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
and nothing here depends on it.
|
|
7
|
+
Work arrives finished, rather than waiting in a chat window for you to open it — though
|
|
8
|
+
you can also just ask it something when you want to.
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
npx @meffecta/agent steps # the whole set-up, in order
|
|
13
|
-
npx @meffecta/agent help # every command
|
|
14
|
-
```
|
|
10
|
+
### → [agent.meffecta.com](https://agent.meffecta.com)
|
|
15
11
|
|
|
16
|
-
|
|
12
|
+
What it is, what you need, and the whole set-up in order. This package (`@meffecta/agent`)
|
|
13
|
+
is the tool that stands one up and operates it.
|
|
17
14
|
|
|
18
|
-
|
|
19
|
-
`worlds/` and `SYSTEM.md`. That file says which GCP project and Cloud Run service this
|
|
20
|
-
deployment is, so a command can never quietly act on the wrong one.
|
|
15
|
+
## What people run it for
|
|
21
16
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
npx @meffecta/agent link-billing # attach billing
|
|
25
|
-
npx @meffecta/agent setup-infra # registry, buckets, service account, service
|
|
26
|
-
npx @meffecta/agent set-secret AGENT_API_SECRET --random
|
|
27
|
-
npx @meffecta/agent set-env GIT_REPO_URL=https://github.com/you/your-content-repo.git
|
|
28
|
-
npx @meffecta/agent deploy # roll out the engine
|
|
29
|
-
npx @meffecta/agent sync-triggers # give it its triggers
|
|
30
|
-
```
|
|
17
|
+
A job is a page of plain-language instructions, so this is a sample rather than a menu —
|
|
18
|
+
the agent does what your jobs say.
|
|
31
19
|
|
|
32
|
-
|
|
33
|
-
|
|
20
|
+
**Sales** — find prospects and check them against your CRM, research each company and its
|
|
21
|
+
decision-maker, leave outreach drafts in the seller's own mailbox for them to send, and put
|
|
22
|
+
a next step on every priority account.
|
|
34
23
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
```
|
|
24
|
+
**Marketing** — one weekly read across traffic, search, ads and campaigns. Website and
|
|
25
|
+
search audits with fixes proposed. Ad reviews, where changes happen only on request. Watches
|
|
26
|
+
form leads, contacts, and competitors' rankings.
|
|
39
27
|
|
|
40
|
-
|
|
28
|
+
**Customer care** — a support inbox that answers or hands over with the findings attached,
|
|
29
|
+
learns from the conversations, and keeps help pages current as things change.
|
|
41
30
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
npx @meffecta/agent env # every setting (secret values never printed)
|
|
47
|
-
npx @meffecta/agent secrets # what is stored, and what the service reads
|
|
48
|
-
npx @meffecta/agent triggers # the Cloud Scheduler jobs and task queue
|
|
49
|
-
npx @meffecta/agent logs --limit 100
|
|
50
|
-
npx @meffecta/agent run morning-brief
|
|
51
|
-
npx @meffecta/agent ask "how did search do last week"
|
|
52
|
-
```
|
|
31
|
+
**Compliance** — review an ISO 27001 document set against the standard, find what is overdue
|
|
32
|
+
or contradicts itself, and draft revisions for a person to approve — sized to your business
|
|
33
|
+
rather than to a template's idea of one. It never records that a control is in place: that
|
|
34
|
+
claim is what an audit tests.
|
|
53
35
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
with no triggers runs nothing while looking perfectly healthy, an always-on one with
|
|
57
|
-
triggers runs every cron twice, a sweep whose cadence no longer matches the inbox poll
|
|
58
|
-
interval checks mail on yesterday's schedule for ever, and a registry that expired the
|
|
59
|
-
image your revision pins will fail at the next cold start rather than the next deploy.
|
|
60
|
-
Every finding carries the command that fixes it, and it exits non-zero on a real problem
|
|
61
|
-
so CI can run it.
|
|
36
|
+
**Engineering** — overnight error triage with fixes proposed as pull requests, a verdict on
|
|
37
|
+
every proposed change, alerts traced to a likely cause, and weekly upkeep.
|
|
62
38
|
|
|
63
|
-
|
|
39
|
+
**Leadership** — a morning brief tailored to each person's role, daily status on what is
|
|
40
|
+
live and in use, and weekly reviews that stay honest about flat weeks.
|
|
64
41
|
|
|
65
|
-
**
|
|
66
|
-
|
|
67
|
-
together, so a script can never provision the wrong shape for the engine it is aimed at.
|
|
68
|
-
`meffecta-agent version` tells you which pair you have.
|
|
42
|
+
**Assistant** — email it anything: a lookup, a draft, a booking, a question. One calendar
|
|
43
|
+
across Google and Microsoft 365. Inbox digests and the week ahead.
|
|
69
44
|
|
|
70
|
-
|
|
71
|
-
reads it; `env` names secret-backed settings without resolving them. Setting one takes the
|
|
72
|
-
value from a pipe, a file, or a hidden prompt — never from your shell history.
|
|
45
|
+
## What it can reach
|
|
73
46
|
|
|
74
|
-
|
|
47
|
+
Shipped with the engine, pointed at your accounts by your jobs:
|
|
75
48
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
49
|
+
| | Reached out of the box |
|
|
50
|
+
|---|---|
|
|
51
|
+
| **Mail & calendar** | Gmail, Microsoft 365, Google Calendar |
|
|
52
|
+
| **Documents** | Drive, Sheets, Docs, Slides |
|
|
53
|
+
| **Your numbers** | GA4, Search Console, Google Ads, PostHog, Ahrefs |
|
|
54
|
+
| **Your data** | BigQuery, Elasticsearch, MongoDB — and logs from Grafana or Coralogix |
|
|
55
|
+
| **The market** | Google's live search results — real rankings, not a web search |
|
|
56
|
+
| **CRM** | HubSpot, reading and writing as separate abilities |
|
|
57
|
+
| **Work & content** | Linear issues and cycles; Webflow pages and CMS, staged before anything goes public |
|
|
58
|
+
| **Slack** | Posts, threads and reactions — and answers when someone @-mentions it |
|
|
59
|
+
| **Infrastructure** | Cloudflare, and a real headless browser for anything without an API |
|
|
60
|
+
| **Your code** | any Git repo as the working directory, with pull requests as the output |
|
|
79
61
|
|
|
80
|
-
|
|
81
|
-
token, and more importantly its run has your content repo cloned and the engine's skills
|
|
82
|
-
mounted, so it can read your existing jobs for house style, your worlds, and
|
|
83
|
-
`systems/` for which systems this deployment can actually reach. It writes a file to
|
|
84
|
-
`jobs/<name>.md` and stops: nothing is committed, pushed or deployed, because that prompt
|
|
85
|
-
is something your agent will run and you should read it first.
|
|
62
|
+
Anything else is a skill you add to your own repo — the engine never needs to know about it.
|
|
86
63
|
|
|
87
|
-
|
|
88
|
-
deployment's timezone, a usable job name, no `inbox:` without `allowFrom:` (the engine
|
|
89
|
-
refuses those, deliberately), an `effort:` the engine accepts, and no silent overwrite of
|
|
90
|
-
an existing job. `--dry-run` prints without writing; `--name` overrides the chosen name.
|
|
64
|
+
## How it works
|
|
91
65
|
|
|
92
|
-
|
|
66
|
+
Your **content repo** holds the jobs, the facts about your business, and the register of
|
|
67
|
+
which systems this deployment may touch. Every run clones it fresh. Push a changed prompt
|
|
68
|
+
and the next run uses it; there is nothing to build and nothing to deploy.
|
|
93
69
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
## Anonymous analytics
|
|
99
|
-
|
|
100
|
-
On by default, and one command to stop:
|
|
101
|
-
|
|
102
|
-
```bash
|
|
103
|
-
meffecta-agent analytics # exactly what is sent, and the current state
|
|
104
|
-
meffecta-agent analytics off # or set DO_NOT_TRACK=1
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
**Sent:** which command ran — matched against the built-in list, never a word you typed —
|
|
108
|
-
whether it worked, how long it took, the class of any error, this CLI's version and the
|
|
109
|
-
engine tag it deploys, Node version, OS and architecture, how you installed it, and whether
|
|
110
|
-
a `deployment.env` was found. Plus a random id generated on your machine, so repeat runs
|
|
111
|
-
count as one install.
|
|
70
|
+
Jobs are triggered by a **schedule**, a **webhook**, or **an email to an address you name**
|
|
71
|
+
— and a job that runs out of time can hand the rest to a follow-up run of itself. Each job
|
|
72
|
+
keeps its own memory across runs, and every prompt, result and transcript lands in a
|
|
73
|
+
write-once audit bucket.
|
|
112
74
|
|
|
113
|
-
|
|
114
|
-
address, file paths, command arguments, secret names or values, job names, prompts — or any
|
|
115
|
-
error *message*. Only the error's class, because messages routinely quote a project id, a
|
|
116
|
-
path, or a line of `gcloud` output.
|
|
75
|
+
## Built to be trusted with the keys
|
|
117
76
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
is silent — analytics can never delay or fail a deploy.
|
|
77
|
+
It runs in **your** GCP project, on **your** credentials, billed to **your** Claude
|
|
78
|
+
subscription. Nothing routes through Meffecta.
|
|
121
79
|
|
|
122
|
-
|
|
80
|
+
A job reaches only the systems your register lists, and reading and changing are separate
|
|
81
|
+
abilities — a reporting job loads the reader and never the writer.
|
|
123
82
|
|
|
124
|
-
|
|
125
|
-
|
|
83
|
+
One shipped skill exists to change a paid account, Google Ads, and it is the most
|
|
84
|
+
constrained thing here: every change is validated against the live account first and only
|
|
85
|
+
applied on a second, explicit run; budgets can only go *down*; a campaign can be paused but
|
|
86
|
+
never deleted; and the limits live in the script, not in the instructions, so no wording can
|
|
87
|
+
talk its way past them.
|
|
126
88
|
|
|
127
|
-
|
|
89
|
+
A job reachable by email must say who may reach it, or it refuses everyone — an omission is
|
|
90
|
+
not consent. Secret values are never printed, by any command.
|
|
128
91
|
|
|
129
|
-
|
|
92
|
+
## Operating it
|
|
130
93
|
|
|
131
94
|
```bash
|
|
132
|
-
|
|
95
|
+
npx @meffecta/agent steps # the set-up, in order
|
|
96
|
+
npx @meffecta/agent help # every command — each also takes --help
|
|
97
|
+
npx @meffecta/agent doctor # the one to run when something feels wrong
|
|
133
98
|
```
|
|
134
99
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
100
|
+
Run commands from your content repo — the directory holding `deployment.env`, which says
|
|
101
|
+
which project and service this deployment is, so a command can never act on the wrong one.
|
|
102
|
+
|
|
103
|
+
**The version you install is the engine you deploy.** Each release records the engine build
|
|
104
|
+
published alongside it, and `deploy` defaults to that image, so tooling and engine cannot
|
|
105
|
+
drift apart. `meffecta-agent version` tells you which pair you have.
|
|
138
106
|
|
|
139
|
-
##
|
|
107
|
+
## Licence
|
|
140
108
|
|
|
141
|
-
|
|
142
|
-
set-up in order, with the command for each step. Every command takes `--help`.
|
|
109
|
+
UNLICENSED — for use by Meffecta deployments.
|
package/engine.json
CHANGED
package/lib/create-job.js
CHANGED
|
@@ -180,7 +180,7 @@ function buildPrompt(description, { timezone, existing }) {
|
|
|
180
180
|
"",
|
|
181
181
|
"Before writing anything, read what this deployment actually is:",
|
|
182
182
|
" - jobs/*.md in your working directory — the house style, and what already exists",
|
|
183
|
-
" - systems/
|
|
183
|
+
" - systems/ — what this deployment can reach, one file per system, and the variables for each",
|
|
184
184
|
" - worlds/ if present — the projects/products a job can be pointed at",
|
|
185
185
|
" - your own available skills — use only skills that exist; never invent a capability",
|
|
186
186
|
"",
|
|
@@ -40,8 +40,8 @@ PART 2 — this deployment's own systems.
|
|
|
40
40
|
|
|
41
41
|
Part 1 tests what the ENGINE knows how to test. It cannot test a system belonging to this
|
|
42
42
|
deployment specifically. The register of those is \`systems/\` in your working directory —
|
|
43
|
-
one file per system
|
|
44
|
-
|
|
43
|
+
one file per system. If it is not there, say so and stop: a deployment with no register has
|
|
44
|
+
no systems of its own that anything can check.
|
|
45
45
|
|
|
46
46
|
Each file's frontmatter says what to do:
|
|
47
47
|
system: what it is
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meffecta/agent",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
4
4
|
"description": "Set up and operate a Meffecta Agent deployment — a self-hosted Claude Code job runner.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
"url": "git+https://github.com/meffecta/agent.git",
|
|
33
33
|
"directory": "cli"
|
|
34
34
|
},
|
|
35
|
+
"homepage": "https://agent.meffecta.com",
|
|
35
36
|
"scripts": {
|
|
36
37
|
"prepack": "node prepack.mjs",
|
|
37
38
|
"postpack": "node prepack.mjs --clean"
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
// Never prints a credential value. Exits 1 if anything configured actually fails.
|
|
9
9
|
|
|
10
10
|
import { execFile } from "node:child_process";
|
|
11
|
-
import { readFileSync } from "node:fs";
|
|
11
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
12
|
+
import { join } from "node:path";
|
|
12
13
|
import { fileURLToPath } from "node:url";
|
|
13
14
|
|
|
14
15
|
const env = process.env;
|
|
@@ -674,8 +675,8 @@ results.sort((a, b) => a.name.localeCompare(b.name));
|
|
|
674
675
|
// because this script ships to EVERY deployment and knows every integration the engine
|
|
675
676
|
// supports — which is always more than any one deployment uses. Listing them individually
|
|
676
677
|
// asks the operator "why is Kleer in my report?", and the honest answer is that it is not
|
|
677
|
-
// theirs and never was. The deployment's own register of what it can reach is
|
|
678
|
-
//
|
|
678
|
+
// theirs and never was. The deployment's own register of what it can reach is `systems/`
|
|
679
|
+
// in its content repo; the catalogue of what it could add is `connect`.
|
|
679
680
|
// Credentials this script has never heard of.
|
|
680
681
|
//
|
|
681
682
|
// A deployment adds its own systems, and their keys are just secrets bound to the service:
|
|
@@ -685,8 +686,8 @@ results.sort((a, b) => a.name.localeCompare(b.name));
|
|
|
685
686
|
// "everything works" while a set-but-never-exercised key sits beside it.
|
|
686
687
|
//
|
|
687
688
|
// So: name them, say plainly that nothing here can test them, and let the run that called
|
|
688
|
-
// this reconcile them against
|
|
689
|
-
//
|
|
689
|
+
// this reconcile them against `systems/` — the deployment's own register does know what
|
|
690
|
+
// they are and which skill reaches them.
|
|
690
691
|
//
|
|
691
692
|
// Known-ness is decided from this file's own source, so the list maintains itself: if the
|
|
692
693
|
// script mentions the variable, or the family it belongs to, it knows about it.
|
|
@@ -736,9 +737,39 @@ console.log(`\n${configured.length - failures.length} working, ${failures.length
|
|
|
736
737
|
if (unknownCredentials.length) {
|
|
737
738
|
// Names only. This script never prints a value, and that holds hardest for the ones it
|
|
738
739
|
// does not understand.
|
|
740
|
+
//
|
|
741
|
+
// Which of them are a PROBLEM, though, is a question this script can answer without
|
|
742
|
+
// knowing anything about the systems themselves: the register travels into every run, so
|
|
743
|
+
// it is right here in the working directory. A credential named in it is deliberate, and
|
|
744
|
+
// proving it works is Part 2's job; one named nowhere is a key no skill will ever reach
|
|
745
|
+
// for, however valid it is. Printing the whole list as a to-do told the operator to
|
|
746
|
+
// register things that were already registered, which is how a real gap gets skimmed
|
|
747
|
+
// past.
|
|
748
|
+
const registered = new Set();
|
|
749
|
+
const registerDir = join(process.cwd(), "systems");
|
|
750
|
+
if (existsSync(registerDir)) {
|
|
751
|
+
for (const entry of readdirSync(registerDir)) {
|
|
752
|
+
if (!entry.endsWith(".md")) continue;
|
|
753
|
+
const text = readFileSync(join(registerDir, entry), "utf8");
|
|
754
|
+
for (const name of unknownCredentials) {
|
|
755
|
+
if (text.includes(name)) registered.add(name);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
const unregistered = unknownCredentials.filter((name) => !registered.has(name));
|
|
739
760
|
console.log(`\nSet, but nothing here knows how to test them (${unknownCredentials.length}):`);
|
|
740
761
|
console.log(` ${unknownCredentials.join(", ")}`);
|
|
741
|
-
|
|
762
|
+
if (!existsSync(registerDir)) {
|
|
763
|
+
// No register to read — say the general thing rather than accuse every one of them.
|
|
764
|
+
console.log(" Each needs a file in systems/ saying which skill reaches it.");
|
|
765
|
+
} else {
|
|
766
|
+
if (registered.size) {
|
|
767
|
+
console.log(` In systems/, so a job can reach them: ${[...registered].sort().join(", ")}`);
|
|
768
|
+
}
|
|
769
|
+
if (unregistered.length) {
|
|
770
|
+
console.log(` Not in systems/, so no skill will find them: ${unregistered.join(", ")}`);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
742
773
|
}
|
|
743
774
|
if (unconfigured.length) {
|
|
744
775
|
console.log(`\nNot set up here (${unconfigured.length}): ${unconfigured.map((r) => r.name).join(", ")}.`);
|