@rubytech/create-maxy-code 0.1.243 → 0.1.246

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.
Files changed (43) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/docs/superpowers/plans/2026-06-04-public-agent-knowledge-delivery.md +230 -0
  3. package/payload/platform/neo4j/schema.cypher +0 -5
  4. package/payload/platform/plugins/admin/mcp/dist/index.js +3 -4
  5. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  6. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +19 -22
  7. package/payload/platform/plugins/admin/skills/public-agent-manager/SKILL.md +38 -72
  8. package/payload/platform/plugins/cloudflare/.claude-plugin/plugin.json +1 -1
  9. package/payload/platform/plugins/cloudflare/PLUGIN.md +10 -7
  10. package/payload/platform/plugins/cloudflare/references/api.md +166 -0
  11. package/payload/platform/plugins/cloudflare/references/d1-data-capture.md +157 -0
  12. package/payload/platform/plugins/cloudflare/references/dashboard-guide.md +6 -6
  13. package/payload/platform/plugins/cloudflare/references/hosting-sites.md +66 -0
  14. package/payload/platform/plugins/cloudflare/references/manual-setup.md +5 -3
  15. package/payload/platform/plugins/cloudflare/skills/cloudflare/SKILL.md +72 -0
  16. package/payload/platform/plugins/docs/references/cloudflare.md +4 -4
  17. package/payload/platform/plugins/docs/references/deployment.md +1 -1
  18. package/payload/platform/plugins/docs/references/internals.md +3 -6
  19. package/payload/platform/plugins/memory/PLUGIN.md +2 -2
  20. package/payload/platform/scripts/setup-account.sh +16 -8
  21. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  22. package/payload/platform/services/claude-session-manager/dist/http-server.js +1 -32
  23. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  24. package/payload/platform/services/claude-session-manager/dist/jsonl-tail.d.ts +12 -0
  25. package/payload/platform/services/claude-session-manager/dist/jsonl-tail.d.ts.map +1 -1
  26. package/payload/platform/services/claude-session-manager/dist/jsonl-tail.js +1 -1
  27. package/payload/platform/services/claude-session-manager/dist/jsonl-tail.js.map +1 -1
  28. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +7 -33
  29. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
  30. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +150 -132
  31. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  32. package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts +2 -1
  33. package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts.map +1 -1
  34. package/payload/platform/services/claude-session-manager/dist/system-prompt.js +39 -6
  35. package/payload/platform/services/claude-session-manager/dist/system-prompt.js.map +1 -1
  36. package/payload/platform/templates/agents/public/IDENTITY.md +9 -62
  37. package/payload/platform/templates/specialists/agents/personal-assistant.md +2 -2
  38. package/payload/server/{chunk-ZY6W3UA2.js → chunk-JMEX5NRX.js} +1 -22
  39. package/payload/server/maxy-edge.js +1 -1
  40. package/payload/server/server.js +7 -21
  41. package/payload/platform/plugins/cloudflare/skills/setup-tunnel/SKILL.md +0 -55
  42. package/payload/platform/templates/agents/public/SOUL.md +0 -19
  43. package/payload/platform/templates/agents/public/config.json +0 -9
@@ -0,0 +1,166 @@
1
+ # Cloudflare API — master token, minted narrow tokens, endpoint map
2
+
3
+ The Cloudflare REST API is a permitted surface on this install. It is how the agent does DNS edits, Pages deploys, D1 queries, Access policies, and apex-CNAME creation without driving the dashboard. This reference is the library: where the canonical docs live, how auth works (one operator-provisioned master token; the agent mints short-lived narrow tokens from it), where the master is stored, and the curated endpoints worth knowing.
4
+
5
+ Canonical reference (always the source of truth for request shapes, never mirror it wholesale here): **https://developers.cloudflare.com/api/**
6
+
7
+ ---
8
+
9
+ ## Auth model — one master, many minted narrow tokens
10
+
11
+ There are two distinct tokens in play. Keep them separate.
12
+
13
+ - **Master token** — fully-scoped, long-lived, provisioned **once** by the operator in the dashboard (see § Provisioning the master token, below). Broad enough to manage Pages, D1, DNS, **and** create API tokens. The agent reads it only to mint narrow tokens. It is never passed to `wrangler`, never put on a command line that gets echoed, never printed.
14
+ - **Minted narrow token** — scoped to exactly one operation class (a single-zone DNS edit, a one-project Pages deploy, a D1 query), short-lived, created by the agent via the API call below. Exported into the environment for the one `wrangler` / API call, then discarded. Never written to disk, never committed, never echoed into chat.
15
+
16
+ Why mint instead of hand-rolling: the operator provisions the master once; every per-operation token is minted by the agent on demand, so the operator never hand-crafts scoped tokens and no broad token is ever exported to a tool that could log it.
17
+
18
+ ---
19
+
20
+ ## Master token storage — account-scoped secrets file
21
+
22
+ Store the master at an account-scoped secrets file, **not** in any deployable project tree:
23
+
24
+ ```
25
+ ~/<brand>-code/data/accounts/<accountId>/secrets/cloudflare.env # mode 600, umask 077
26
+ ```
27
+
28
+ (worked example: `~/realagent-code/data/accounts/<accountId>/secrets/cloudflare.env`)
29
+
30
+ It holds exactly two values:
31
+
32
+ ```
33
+ CLOUDFLARE_API_TOKEN=<master>
34
+ CLOUDFLARE_ACCOUNT_ID=<accountId>
35
+ ```
36
+
37
+ Rationale (binding):
38
+
39
+ 1. **Account-isolated** — under `data/accounts/<accountId>/`, consistent with brand isolation; one account's master never sits where another account's flow can read it.
40
+ 2. **Outside every deployable/git project tree** — so the god-token can never be committed or shipped in a Pages upload. This is the failure mode a project-root `.env` invites: a `.env` next to a site's source gets swept into the `wrangler pages deploy` upload or a `git add .`.
41
+ 3. **Sourced on demand for the master only** — `set -a; . <file>; set +a` to load `CLOUDFLARE_API_TOKEN` + `CLOUDFLARE_ACCOUNT_ID` into the environment for the mint call; per-operation narrow tokens go into the ephemeral environment of their single command, never into this file.
42
+
43
+ Create it once (mode 600, parent dirs 700):
44
+
45
+ ```bash
46
+ ACCOUNT_ID="<accountId>"
47
+ SECRETS_DIR="${HOME}/<brand>-code/data/accounts/${ACCOUNT_ID}/secrets"
48
+ ( umask 077; mkdir -p "${SECRETS_DIR}" )
49
+ # The operator pastes the master token; the agent never echoes it back.
50
+ ( umask 077; printf 'CLOUDFLARE_API_TOKEN=%s\nCLOUDFLARE_ACCOUNT_ID=%s\n' "<master>" "${ACCOUNT_ID}" > "${SECRETS_DIR}/cloudflare.env" )
51
+ chmod 600 "${SECRETS_DIR}/cloudflare.env"
52
+ ```
53
+
54
+ Load the master for a mint call:
55
+
56
+ ```bash
57
+ set -a; . "${SECRETS_DIR}/cloudflare.env"; set +a
58
+ ```
59
+
60
+ ---
61
+
62
+ ## Provisioning the master token (ADVANCED — operator-guided, never automated)
63
+
64
+ This is the one manual, operator-driven step. The agent relays the click-path; it does **not** browser-automate it (no Playwright, no Chrome DevTools, no consent-page driver).
65
+
66
+ 1. Open **https://dash.cloudflare.com/profile/api-tokens** in your browser.
67
+ 2. Click **Create Token** → **Create Custom Token** → **Get started**.
68
+ 3. Name it (e.g. `<brand> master`). Under **Permissions**, add these rows (Account-level unless noted):
69
+ - **Account · Cloudflare Pages · Edit**
70
+ - **Account · D1 · Edit**
71
+ - **Account · API Tokens · Write** ← this is what lets the agent mint narrow tokens
72
+ - **Zone · DNS · Edit** (Zone Resources → the zones you route)
73
+ - **Account · Cloudflare Tunnel · Edit** (only if you want the API to manage tunnels alongside `cloudflared`)
74
+ 4. **Account Resources** → Include → your account. **Zone Resources** → Include → the zones in scope.
75
+ 5. Click **Continue to summary**, then **Create Token**.
76
+ 6. Copy the token **once** — Cloudflare shows it a single time. Paste it into the secrets file (above). The agent stores it without echoing it back.
77
+
78
+ Verify the master works (token value never printed — only the verification result):
79
+
80
+ ```bash
81
+ set -a; . "${SECRETS_DIR}/cloudflare.env"; set +a
82
+ curl -sS -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \
83
+ "https://api.cloudflare.com/client/v4/user/tokens/verify" | jq '.result.status'
84
+ # expect: "active"
85
+ ```
86
+
87
+ ---
88
+
89
+ ## Minting a narrow token
90
+
91
+ The agent mints a per-operation token from the master via `POST /accounts/{account_id}/tokens`. Scope it to the single operation, give it a short TTL, export it for the one call, discard it.
92
+
93
+ ```bash
94
+ set -a; . "${SECRETS_DIR}/cloudflare.env"; set +a # loads the master + account id
95
+
96
+ # Example: a one-project Pages-deploy token. Adjust the policy for the operation.
97
+ MINTED=$(curl -sS -X POST \
98
+ -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \
99
+ -H "Content-Type: application/json" \
100
+ "https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/tokens" \
101
+ --data @- <<'JSON' | jq -r '.result.value'
102
+ {
103
+ "name": "ephemeral-pages-deploy",
104
+ "policies": [{
105
+ "effect": "allow",
106
+ "resources": { "com.cloudflare.api.account.<accountId>": "*" },
107
+ "permission_groups": [{ "id": "<pages-edit-permission-group-id>", "name": "Pages Write" }]
108
+ }],
109
+ "expires_on": "<iso8601-a-few-minutes-out>"
110
+ }
111
+ JSON
112
+ )
113
+
114
+ # Use it for exactly one command, in this command's environment only:
115
+ CLOUDFLARE_API_TOKEN="${MINTED}" wrangler pages deploy ./dist --project-name <project> --branch=main
116
+
117
+ unset MINTED # discard; never written to disk, never echoed
118
+ ```
119
+
120
+ Look up `<pages-edit-permission-group-id>` (and the ids for DNS Edit, D1 Edit, etc.) once via `GET /accounts/{account_id}/tokens/permission_groups`; they are stable per account.
121
+
122
+ **Redaction is binding.** Every example above pipes the token into a variable or an `Authorization` header and never to stdout. The agent surfaces the operation as verb + target — "minting a Pages-deploy token", "creating CNAME `chat.example.com`" — never the secret. A failure surfaces the API error body with any `Authorization` value masked.
123
+
124
+ ---
125
+
126
+ ## Curated endpoint map
127
+
128
+ Request/response shapes live at the canonical docs URL; this is the index of what to reach for. `${ACC}` = `CLOUDFLARE_ACCOUNT_ID`, `${ZONE}` = the zone id, `${TOKEN}` = a **minted narrow** token.
129
+
130
+ ### Token create / verify
131
+ - `GET /user/tokens/verify` — confirm a token is active.
132
+ - `POST /accounts/${ACC}/tokens` — mint a narrow token (see above).
133
+ - `GET /accounts/${ACC}/tokens/permission_groups` — resolve permission-group ids for scoping.
134
+
135
+ ### DNS records (zone-scoped; needs **Zone · DNS · Edit**)
136
+ - `GET /zones/${ZONE}/dns_records` — list / find a record id.
137
+ - `POST /zones/${ZONE}/dns_records` — create. For an **apex CNAME**, set `"type":"CNAME"`, `"name":"@"` (or the bare zone name), `"content":"<UUID>.cfargotunnel.com"`, `"proxied":true` — Cloudflare flattens it automatically. This is the API equivalent of the dashboard apex edit in `dashboard-guide.md`.
138
+ - `PUT/PATCH /zones/${ZONE}/dns_records/{id}` — update. `DELETE …/{id}` — remove a stray record.
139
+
140
+ ```bash
141
+ curl -sS -X POST -H "Authorization: Bearer ${TOKEN}" -H "Content-Type: application/json" \
142
+ "https://api.cloudflare.com/client/v4/zones/${ZONE}/dns_records" \
143
+ --data '{"type":"CNAME","name":"@","content":"<UUID>.cfargotunnel.com","proxied":true}' \
144
+ | jq '{ok:.success, name:.result.name}'
145
+ ```
146
+
147
+ ### Zones
148
+ - `GET /zones?account.id=${ACC}` — list zones on the account; find a zone id by name (`?name=example.com`).
149
+
150
+ ### Tunnels (Account · Cloudflare Tunnel)
151
+ - `GET /accounts/${ACC}/cfd_tunnel` — list tunnels.
152
+ - `POST /accounts/${ACC}/cfd_tunnel` — create. `DELETE …/{tunnel_id}` — delete.
153
+ - The OAuth/`cloudflared` path in `manual-setup.md` remains the primary tunnel flow; use the API only when an end-to-end programmatic run is wanted.
154
+
155
+ ### Access (Zero Trust) applications + policies
156
+ - `POST /accounts/${ACC}/access/apps` and `POST /accounts/${ACC}/access/apps/{app_id}/policies` — author an Access application + policy programmatically. The dashboard click-path in `dashboard-guide.md` § "Author an Access policy" is the alternative for operators who prefer to click.
157
+
158
+ ---
159
+
160
+ ## When to use which path
161
+
162
+ - **Tunnel create/route/run** → `cloudflared` (OAuth cert), per `manual-setup.md`. The API can manage tunnels too, but the cert path is the established one.
163
+ - **Apex CNAME** → API (above) or dashboard (`dashboard-guide.md`). Either flattens correctly.
164
+ - **Pages deploy** → `wrangler` with a minted Pages-Edit token, per `hosting-sites.md`.
165
+ - **D1 read/write** → `wrangler d1 execute --remote` with a minted D1-Edit token, per `d1-data-capture.md`.
166
+ - **Inspecting account state** (which zones, which tunnels) → API `GET` with a read-scoped minted token, or the dashboard.
@@ -0,0 +1,157 @@
1
+ # Capturing form submissions into Cloudflare D1
2
+
3
+ This is the established pattern for turning a static site's contact / waitlist form into durable, queryable leads: the form POSTs to a **Pages Function**, the Function inserts a row into a **Cloudflare D1** database, and the agent reads and sweeps new rows with `wrangler d1 execute --remote`. It is live on `realagent.pages.dev` today — the worked example below is that deployment, generalized with placeholders.
4
+
5
+ Pair this with `hosting-sites.md` (how the site itself gets deployed) and `api.md` (the master token + mint-narrow discipline that authenticates every `wrangler` call).
6
+
7
+ ---
8
+
9
+ ## The single most common breakage — token scope
10
+
11
+ A Pages-only token **cannot touch D1**. The deploy succeeds, the form renders, and every submission silently 500s at the D1 insert. The token used for D1-backed Pages work must carry **both**:
12
+
13
+ - **Account · Cloudflare Pages · Edit**
14
+ - **Account · D1 · Edit**
15
+
16
+ Mint a narrow token that includes both permission groups (see `api.md` § Minting a narrow token) before any `wrangler d1` or D1-backed deploy command. This was observed live in the session that built `realagent.pages.dev`; it is the first thing to check when captures stop arriving.
17
+
18
+ ---
19
+
20
+ ## 0. Mint the Pages-+-D1 token
21
+
22
+ Every command below uses `${MINTED_PAGES_D1}` — a narrow token scoped to **both** Pages Edit and D1 Edit, minted from the master per `api.md` § Minting a narrow token. Mint it once at the start of the session and export it; it is never written to disk or echoed:
23
+
24
+ ```bash
25
+ set -a; . "${SECRETS_DIR}/cloudflare.env"; set +a # loads master + account id
26
+ MINTED_PAGES_D1=$(curl -sS -X POST \
27
+ -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \
28
+ -H "Content-Type: application/json" \
29
+ "https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/tokens" \
30
+ --data @- <<'JSON' | jq -r '.result.value'
31
+ {
32
+ "name": "ephemeral-pages-d1",
33
+ "policies": [{
34
+ "effect": "allow",
35
+ "resources": { "com.cloudflare.api.account.<accountId>": "*" },
36
+ "permission_groups": [
37
+ { "id": "<pages-edit-permission-group-id>", "name": "Pages Write" },
38
+ { "id": "<d1-edit-permission-group-id>", "name": "D1 Write" }
39
+ ]
40
+ }],
41
+ "expires_on": "<iso8601-a-few-minutes-out>"
42
+ }
43
+ JSON
44
+ )
45
+ ```
46
+
47
+ Resolve the two permission-group ids once via `GET /accounts/{account_id}/tokens/permission_groups` (see `api.md`). When the work is done, `unset MINTED_PAGES_D1`.
48
+
49
+ ---
50
+
51
+ ## 1. Create the database
52
+
53
+ ```bash
54
+ CLOUDFLARE_API_TOKEN="${MINTED_PAGES_D1}" wrangler d1 create <db-name>
55
+ # worked example: wrangler d1 create realagent-leads
56
+ ```
57
+
58
+ `wrangler` prints the database `name` and `database_id`. Copy the `database_id` into `wrangler.toml` (next step). The token value is never printed — only the database identifiers.
59
+
60
+ ## 2. Bind the database in `wrangler.toml`
61
+
62
+ The binding name (`DB` below) is the variable the Pages Function reads off `env`. Keep `wrangler.toml` in the site's project root — it carries no secret, only the database id.
63
+
64
+ ```toml
65
+ name = "<project>" # worked example: realagent
66
+ pages_build_output_dir = "dist" # or the framework's output dir
67
+
68
+ [[d1_databases]]
69
+ binding = "DB"
70
+ database_name = "<db-name>" # realagent-leads
71
+ database_id = "<database_id>" # from step 1
72
+ ```
73
+
74
+ ## 3. Create the table
75
+
76
+ Apply the schema to the remote database (`--remote` targets the live D1, not a local replica):
77
+
78
+ ```bash
79
+ CLOUDFLARE_API_TOKEN="${MINTED_PAGES_D1}" wrangler d1 execute <db-name> --remote --command \
80
+ "CREATE TABLE IF NOT EXISTS leads (
81
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
82
+ name TEXT,
83
+ email TEXT NOT NULL,
84
+ message TEXT,
85
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
86
+ swept INTEGER NOT NULL DEFAULT 0
87
+ );"
88
+ ```
89
+
90
+ The `swept` column is the read-cursor: a row is `swept = 0` until the agent has ingested it, then flipped to `1`. This is what makes "show me new leads" a deterministic query rather than a guess.
91
+
92
+ ## 4. The Pages Function — `functions/api/contact.ts`
93
+
94
+ A file at `functions/api/contact.ts` is served at `POST /api/contact` automatically (Pages Functions route by file path). It reads the `DB` binding and inserts a row. No secret lives in this file — the D1 binding is injected by the platform at runtime.
95
+
96
+ ```ts
97
+ interface Env { DB: D1Database }
98
+
99
+ export const onRequestPost: PagesFunction<Env> = async ({ request, env }) => {
100
+ const form = await request.formData();
101
+ const email = String(form.get("email") ?? "").trim();
102
+ if (!email) return new Response("email required", { status: 400 });
103
+
104
+ await env.DB
105
+ .prepare("INSERT INTO leads (name, email, message) VALUES (?, ?, ?)")
106
+ .bind(String(form.get("name") ?? ""), email, String(form.get("message") ?? ""))
107
+ .run();
108
+
109
+ return new Response(null, { status: 303, headers: { Location: "/thanks" } });
110
+ };
111
+ ```
112
+
113
+ The site's form posts to it:
114
+
115
+ ```html
116
+ <form method="POST" action="/api/contact">
117
+ <input name="email" type="email" required>
118
+ <input name="name">
119
+ <textarea name="message"></textarea>
120
+ <button>Join the waitlist</button>
121
+ </form>
122
+ ```
123
+
124
+ ## 5. Deploy
125
+
126
+ Deploy via `hosting-sites.md`. The binding in `wrangler.toml` is what wires the deployed Function to D1; the deploy token must carry both Pages Edit and D1 Edit (above).
127
+
128
+ ## 6. Read and sweep new submissions
129
+
130
+ Read everything not yet ingested:
131
+
132
+ ```bash
133
+ CLOUDFLARE_API_TOKEN="${MINTED_PAGES_D1}" wrangler d1 execute <db-name> --remote --json --command \
134
+ "SELECT id, name, email, message, created_at FROM leads WHERE swept = 0 ORDER BY id;"
135
+ ```
136
+
137
+ After ingesting those rows (e.g. writing them into the graph), mark them swept so the next read returns only newer ones:
138
+
139
+ ```bash
140
+ CLOUDFLARE_API_TOKEN="${MINTED_PAGES_D1}" wrangler d1 execute <db-name> --remote --command \
141
+ "UPDATE leads SET swept = 1 WHERE swept = 0;"
142
+ ```
143
+
144
+ ---
145
+
146
+ ## Outcome contract
147
+
148
+ D1 capture is done when a **test POST to the live form** appears in the unswept set:
149
+
150
+ ```bash
151
+ curl -sS -X POST -d "email=test@example.com&name=verify" "https://<project>.pages.dev/api/contact" -i | head -1
152
+ # then:
153
+ CLOUDFLARE_API_TOKEN="${MINTED_PAGES_D1}" wrangler d1 execute <db-name> --remote --command \
154
+ "SELECT email FROM leads WHERE swept = 0;"
155
+ ```
156
+
157
+ The test email appearing in that `SELECT` is the proof. A 200/303 on the POST alone is not — the row in D1 is the contract. Surface the operation as verb + target ("inserting a test lead", "reading unswept rows from `realagent-leads`"); the token value never appears.
@@ -105,12 +105,12 @@ Use this when you need to audit which hostnames are pointing at which `<UUID>.cf
105
105
 
106
106
  ## Author an Access policy for SSH or SMB
107
107
 
108
- When the agent adds an SSH or SMB ingress hostname (per `references/manual-setup.md`), it surfaces an
109
- `ACTION REQUIRED` block naming this click-path. The agent does NOT
110
- create the Access policy Cloudflare API/SDK is banned
111
- (`feedback_cf_api_total_eradication`) and `cloudflared` CLI has no
112
- Access-application create subcommand so the operator must author it
113
- in the dashboard before off-LAN clients can reach the Pi.
108
+ When the agent adds an SSH or SMB ingress hostname (per `references/manual-setup.md`),
109
+ the Access policy must exist before off-LAN clients can reach the Pi. There are two
110
+ paths: the agent can author it via the Cloudflare API with a minted Access-scoped
111
+ token (see `references/api.md` § Access), or the operator can author it by hand in the
112
+ dashboard with the click-path below. `cloudflared` CLI has no Access-application create
113
+ subcommand, so the dashboard path is the manual alternative to the API.
114
114
 
115
115
  1. Click **Zero Trust** in the sidebar.
116
116
  2. Click **Access** → **Applications**.
@@ -0,0 +1,66 @@
1
+ # Deploying a site to Cloudflare Pages
2
+
3
+ How to put a static or Next.js site on Cloudflare Pages via `wrangler`, the way `realagent.pages.dev` is deployed. This covers the build → deploy → verify loop and the Next.js specifics. Auth is a minted narrow token per `api.md`; if the site also captures form data, read `d1-data-capture.md` for the dual Pages-Edit **and** D1-Edit scope.
4
+
5
+ This is distinct from `references/serving-published-sites.md`, which serves a platform-published site at a custom domain through the brand's **cloudflared tunnel**. This reference is about **Cloudflare Pages** — Cloudflare hosts the build, not the install device.
6
+
7
+ ---
8
+
9
+ ## When to use Pages vs the tunnel
10
+
11
+ - **Cloudflare Pages** (this reference) — a standalone marketing/landing/app site that Cloudflare builds and serves on its edge, optionally with Pages Functions + D1. Use when the site is its own project and you want Cloudflare to host it.
12
+ - **The brand tunnel** (`manual-setup.md` + `serving-published-sites.md`) — expose something running on the install device at a custom domain. Use when the content is served by the platform itself.
13
+
14
+ ---
15
+
16
+ ## 1. Build the site
17
+
18
+ Produce the static output the framework emits.
19
+
20
+ - **Static / Vite / Astro:** `npm run build` → output in `dist/` (or the framework default).
21
+ - **Next.js:** Pages needs a static or edge-compatible build. For a fully static site use `output: "export"` in `next.config.js` and `npm run build` → output in `out/`. For a Next.js app with server routes, deploy through the Pages adapter (`@cloudflare/next-on-pages`): `npx @cloudflare/next-on-pages` → output in `.vercel/output/static`.
22
+
23
+ ## 2. Configure `wrangler.toml`
24
+
25
+ ```toml
26
+ name = "<project>" # the Pages project name, e.g. realagent
27
+ pages_build_output_dir = "<output-dir>" # dist | out | .vercel/output/static
28
+ compatibility_date = "2024-01-01"
29
+ compatibility_flags = ["nodejs_compat"] # required for next-on-pages and most Functions
30
+ ```
31
+
32
+ If the site captures form data, add the `[[d1_databases]]` binding from `d1-data-capture.md` here.
33
+
34
+ ## 3. Mint a deploy token
35
+
36
+ A Pages deploy needs **Account · Cloudflare Pages · Edit**. If the site has Pages Functions hitting D1, the token also needs **Account · D1 · Edit** (the single most common breakage — see `d1-data-capture.md`). Mint it per `api.md` § Minting a narrow token:
37
+
38
+ ```bash
39
+ set -a; . "${SECRETS_DIR}/cloudflare.env"; set +a
40
+ # MINTED = a narrow token scoped to Pages Edit (+ D1 Edit if the site uses D1)
41
+ ```
42
+
43
+ ## 4. Deploy
44
+
45
+ ```bash
46
+ CLOUDFLARE_API_TOKEN="${MINTED}" wrangler pages deploy <output-dir> \
47
+ --project-name <project> --branch=main
48
+ ```
49
+
50
+ `--branch=main` deploys to the production alias (`https://<project>.pages.dev`); any other branch name produces a preview URL instead. The first deploy of a new project name creates the project. The token value is never printed — `wrangler` prints the deployment URL, which is what gets surfaced.
51
+
52
+ ## 5. Custom domain (optional)
53
+
54
+ Attach a custom domain to the Pages project in the dashboard (**Workers & Pages → your project → Custom domains → Set up a domain**), or via the API. Cloudflare provisions the certificate and the CNAME automatically when the zone is on the same account.
55
+
56
+ ---
57
+
58
+ ## Outcome contract
59
+
60
+ Hosting is done when the deployed URL serves the **new** build:
61
+
62
+ ```bash
63
+ curl -s "https://<project>.pages.dev/" | head
64
+ ```
65
+
66
+ The response showing the new markup is the proof. A successful `wrangler` exit alone is not the contract — the live URL returning the new content is. Surface the operation as verb + target ("deploying Pages project `realagent`"); the token value never appears in chat or stdout.
@@ -293,9 +293,11 @@ does this on every Pi). The script skips the SMB ingress with
293
293
  `[tunnel-install] smb-ingress-skipped reason=samba-not-provisioned`
294
294
  rather than failing.
295
295
 
296
- **Access policy is dashboard-only.** Cloudflare API/SDK is forbidden;
297
- `cloudflared` CLI has no Access-application create subcommand. After
298
- the ingress is in place, author the policy in the dashboard:
296
+ **Access policy API or dashboard.** `cloudflared` CLI has no
297
+ Access-application create subcommand, so author the policy either via
298
+ the Cloudflare API with a minted Access-scoped token (see
299
+ `references/api.md` § Access) or by hand in the dashboard. After the
300
+ ingress is in place, the dashboard path is:
299
301
 
300
302
  ```
301
303
  Cloudflare → Zero Trust → Access → Applications → Add → Self-hosted
@@ -0,0 +1,72 @@
1
+ ---
2
+ name: cloudflare
3
+ description: Cloudflare operations for the install — tunnel setup/diagnosis/reset, DNS edits, Pages hosting, and D1 data capture. The agent drives `cloudflared` and `wrangler` directly via Bash and reads the matching reference before each operation class; success is always a live behavioural signal (external HTTP 200, a deployed URL, a D1 round-trip), never an exit code.
4
+ ---
5
+
6
+ # Cloudflare operations
7
+
8
+ This is the entry point for every Cloudflare task on the install. Pick the operation class, read the matching reference, run the command via Bash, relay the literal output, and prove the outcome with a live signal. There are no Cloudflare MCP tools; the plugin registers none. The agent never browser-automates the dashboard — the operator clicks where a click is genuinely required.
9
+
10
+ | You want to… | Read | Outcome contract |
11
+ |---|---|---|
12
+ | Stand up / diagnose / reset a tunnel so a hostname is reachable | `references/manual-setup.md` | external `curl -I https://<hostname>` → `200` |
13
+ | Switch accounts, edit an apex CNAME by hand, or other dashboard-only clicks | `references/dashboard-guide.md` | the click-path completed in the operator's browser |
14
+ | Tear down corrupt tunnel state and start clean | `references/reset-guide.md` | a fresh `manual-setup.md` run reaches `200` |
15
+ | Call the Cloudflare API (DNS, zones, tunnels, Access, token mint) | `references/api.md` | the API call returns success and the change is observable |
16
+ | Deploy a static / Next.js site to Cloudflare Pages | `references/hosting-sites.md` | the deployed URL serves the new build |
17
+ | Capture form/waitlist submissions into a database | `references/d1-data-capture.md` | a test POST appears in `SELECT … WHERE swept = 0` |
18
+
19
+ ## Two auth paths, by operation class
20
+
21
+ - **Tunnel auth is OAuth.** `cloudflared tunnel login` writes `cert.pem`; the operator clicks the linkified OAuth URL in their own browser. This is the only path for tunnel create/route/run. See `references/manual-setup.md`.
22
+ - **API auth is the master token.** The operator provisions one fully-scoped master token once (an **advanced**, operator-guided dashboard step — the agent does not automate it) and stores it at the account-scoped secrets file. The agent reads the master only to **mint a narrowly-scoped, short-lived token** for each operation — a single-zone DNS edit, a one-project Pages deploy, a D1 query — and exports that ephemeral token for the one call. See `references/api.md` for the storage convention, the mint flow, and the binding redaction discipline.
23
+
24
+ Neither the master token nor any minted token is ever written into a project tree, committed, or echoed into chat.
25
+
26
+ ## Outcome contracts — what "done" means
27
+
28
+ Every Cloudflare operation proves itself with a live behavioural signal surfaced verbatim in chat:
29
+
30
+ - **Tunnel:** `curl -I https://<hostname>` from outside the local network returns `HTTP/2 200` (or `HTTP/1.1 200 OK`). No state file, no `result=ok` line, no "service is active" claim substitutes. If the curl returns anything else, diagnose with `cloudflared tunnel info <tunnelId>` and `systemctl --user status ${BRAND}-cloudflared.service` and recover per `references/manual-setup.md`.
31
+ - **Hosting:** the deployed Pages URL returns the new build (`curl -s https://<project>.pages.dev/ | head` shows the new markup).
32
+ - **D1 capture:** a test POST to the live form appears in `wrangler d1 execute <db> --remote --command "SELECT … WHERE swept = 0"`.
33
+
34
+ ## Inputs (tunnel)
35
+
36
+ Four inputs come from the operator in chat: the admin FQDN, optional public FQDN, optional apex FQDN, and the admin password. `BRAND` is derived from disk — never hardcoded — with `BRAND=$(jq -r .hostname ~/.<configDir>/brand.json)`. The same install can host different brands on different ports; `brand.json.hostname` is the only authoritative source.
37
+
38
+ ## Execution
39
+
40
+ The agent reads the relevant reference and executes its steps with Bash. Every `cloudflared` / `wrangler` / `curl` invocation's stdout and stderr are relayed into chat verbatim — minus any secret, which is always redacted. The OAuth URL printed by `cloudflared tunnel login` is linkified by the native PTY; the operator clicks it in their own browser. The agent does not spawn a browser, automate the Cloudflare consent page, or drive the dashboard via Playwright or Chrome DevTools.
41
+
42
+ Tunnel mutations the agent performs from `references/manual-setup.md` (each one only after reading the relevant step):
43
+
44
+ - `cloudflared tunnel login` — emits the OAuth URL; cert lands at `~/.cloudflared/cert.pem` after the operator authorises.
45
+ - `cloudflared tunnel --origincert <cert> create <name>` — produces `<tunnelId>.json` credentials.
46
+ - Write `~/.${BRAND}/cloudflared/config.yml` (ingress block per the runbook).
47
+ - `cloudflared tunnel --origincert <cert> route dns <tunnelId> <hostname>` — one call per non-apex hostname.
48
+ - For non-admin hostnames not starting with `public.`, append to `~/.${BRAND}/alias-domains.json` so `isPublicHost()` treats them as public.
49
+ - Install + start the `${BRAND}-cloudflared.service` user unit (`systemctl --user daemon-reload && systemctl --user enable --now ${BRAND}-cloudflared.service`).
50
+
51
+ After the service is up, the agent runs `curl -I https://<admin-hostname>` and pastes the response. The setup-done claim only fires when a `200` line appears in that response.
52
+
53
+ ## Apex hostnames
54
+
55
+ The `cloudflared` CLI cannot route apex records (e.g. `maxy.chat`) — standard DNS forbids a CNAME at the zone apex. There are now two ways to create the apex record: the operator edits the apex CNAME in the dashboard (`references/dashboard-guide.md` § "Edit an apex CNAME"), or the agent creates it via the Cloudflare API with a minted DNS-scoped token (`references/api.md` § DNS records). Either reaches the same flattened-CNAME result; pick the dashboard path when the operator prefers to click, the API path when an end-to-end agent run is wanted.
56
+
57
+ ## Reset
58
+
59
+ When local Cloudflare state is corrupt or the operator wants to start from a known-good cert, follow `references/reset-guide.md`. The agent issues the relevant `cloudflared tunnel delete` and `rm -rf ~/.${BRAND}/cloudflared/` commands in Bash, then re-runs the setup steps above.
60
+
61
+ ## Tool discipline — binding
62
+
63
+ When the operator's request touches Cloudflare, the agent's permitted actions are:
64
+
65
+ - Invoke `cloudflared` via Bash, following `references/manual-setup.md`.
66
+ - Invoke `wrangler` and the Cloudflare API via Bash, following `references/api.md`, `references/hosting-sites.md`, and `references/d1-data-capture.md`, using a freshly-minted narrow token per operation.
67
+ - Write `config.yml` and `alias-domains.json` per the runbook.
68
+ - Install and start the brand's cloudflared user service.
69
+ - Quote `references/manual-setup.md`, `references/reset-guide.md`, or `references/dashboard-guide.md` verbatim when a dashboard click-path is the right tool.
70
+ - Verify reachability via `curl -I https://<hostname>` and surface the response.
71
+
72
+ The agent does not drive the dashboard via Playwright or Chrome DevTools, and does not browser-automate master-token creation. It does not synthesise `cloudflared` flag combinations from web search or training — every command comes from the runbook. It never writes a token to disk in a project tree, commits one, or prints one into chat. When a step fails, the agent reports the exact output, names the recovery step from `references/reset-guide.md`, and stops. Improvisation — "let me try a different flag" or "let me drive the dashboard myself" — is the behaviour this rule exists to prevent.
@@ -1,6 +1,6 @@
1
1
  # Cloudflare Tunnel — the dashboard is the source of truth
2
2
 
3
- Each installation has its own Cloudflare account. Sign-in is OAuth: the agent invokes `cloudflared tunnel login` via Bash; the Cloudflare Authorize URL streams into the admin chat PTY and the native terminal renders it as a clickable link. Click it, authorise in your own browser, and `cloudflared` writes `cert.pem` to the brand's config directory. The agent never reads or mutates Cloudflare account state directly whatever you see in your logged-in dashboard is the single source of truth. When something needs doing on the account side (adding a domain, deleting a stray entry, switching accounts), the agent relays the click-paths; you run them in your browser.
3
+ Each installation has its own Cloudflare account. The **tunnel** sign-in is OAuth: the agent invokes `cloudflared tunnel login` via Bash; the Cloudflare Authorize URL streams into the admin chat PTY and the native terminal renders it as a clickable link. Click it, authorise in your own browser, and `cloudflared` writes `cert.pem` to the brand's config directory. For **everything else** (DNS, Pages, D1, Access) the agent uses the Cloudflare API, authenticated by a short-lived narrow token it mints from a master token you provision once in the dashboard (an advanced step the agent never automates). Some account-side jobs — adding a domain, switching accounts are still easiest in your browser, and the agent relays those click-paths; the rest it can do directly via the API.
4
4
 
5
5
  ## Identity model
6
6
 
@@ -8,10 +8,10 @@ Each installation has its own Cloudflare account. Sign-in is OAuth: the agent in
8
8
  |------|--------|
9
9
  | **Product identity** (Maxy vs Real Agent) | `brand.json` (`productName`, `configDir`) — known at install. |
10
10
  | **Cloudflare account identity** | `cert.pem` from OAuth. One account per brand per device. |
11
- | **Domain scope** (which zones the operator can route) | Live Cloudflare dashboard — the operator picks the zone in the dashboard during OAuth or names it in chat. The agent does not enumerate zones programmatically. |
11
+ | **Domain scope** (which zones the operator can route) | The operator picks the zone in the dashboard during OAuth or names it in chat; the agent can also enumerate zones via the API with a minted read-scoped token. |
12
12
  | **Local tunnel state** | `~/{configDir}/cloudflared/` — `cert.pem`, `<UUID>.json`, `config.yml`, `alias-domains.json`. |
13
13
 
14
- There is no token-based auth for the operator-owned path (Mode A). To switch Cloudflare accounts, the agent runs the reset flow from `plugins/cloudflare/references/reset-guide.md` (deletes the cert and every tunnel on the current account), then the manual-setup flow again — `cloudflared tunnel login` picks a fresh account when you sign in.
14
+ Tunnel auth on the operator-owned path (Mode A) is the OAuth cert (`cert.pem`); API operations use a narrow token the agent mints from your master token. To switch Cloudflare accounts, the agent runs the reset flow from `plugins/cloudflare/references/reset-guide.md` (deletes the cert and every tunnel on the current account), then the manual-setup flow again — `cloudflared tunnel login` picks a fresh account when you sign in.
15
15
 
16
16
  ## Setup flow
17
17
 
@@ -97,6 +97,6 @@ The most common cause is wrong nameservers on the domain. The domain must use Cl
97
97
 
98
98
  **Does:** invokes `cloudflared` directly via Bash, following `plugins/cloudflare/references/manual-setup.md` step by step; quotes click-paths from the reference files verbatim; verifies external reachability with `curl -I` and surfaces the response.
99
99
 
100
- **Does not:** drive the Cloudflare dashboard via Playwright, synthesise alternative `cloudflared` flag sequences not in the runbook, call any Cloudflare API or SDK, write or edit `cert.pem` / `config.yml` directly outside the runbook's instructions.
100
+ **Does not:** drive the Cloudflare dashboard via Playwright, browser-automate master-token creation, synthesise alternative `cloudflared` flag sequences not in the runbook, write or echo any API token, write or edit `cert.pem` / `config.yml` directly outside the runbook's instructions.
101
101
 
102
102
  When a command fails, the agent reports the failure and cites the relevant recovery step. It does not improvise.
@@ -70,7 +70,7 @@ Grep for both in `~/.<brand>/logs/install-*.log`. Absence after a clean install
70
70
 
71
71
  The first user-domain write the agent attempts (e.g. recording who the operator is) hits the graph-write gate's `Write blocked (no-admin-user)` or `Write blocked (no-local-business)` error. The agent then asks the persona question, persists the answer through the `business-profile` skill or `profile-update.personFields`, and proceeds. The error itself is the signal — grep `Write blocked` in `~/.<brand>/logs/server.log` to confirm.
72
72
 
73
- Cloudflare, WhatsApp, Telegram, and any other dormant capability surfaces on owner request via the `<dormant-plugins>` sentinel the manager injects per-spawn. Execution is the existing plugin skill (`cloudflare:setup-tunnel`, etc.) — no banner, no per-step flag.
73
+ Cloudflare, WhatsApp, Telegram, and any other dormant capability surfaces on owner request via the `<dormant-plugins>` sentinel the manager injects per-spawn. Execution is the existing plugin skill (`cloudflare:cloudflare`, etc.) — no banner, no per-step flag.
74
74
 
75
75
  ### Per-spawn system-prompt sentinels
76
76
 
@@ -223,7 +223,7 @@ When `search` is true and `query` is non-null, the rewritten query replaces the
223
223
 
224
224
  ### Knowledge retrieval gate
225
225
 
226
- On the public PTY surface the agent itself decides when to call `memory-search` there is no server-side classifier interposed between the user message and the agent's first tool call. KNOWLEDGE.md (when present) is assembled into the agent's system prompt at spawn time. Whether `memory-search` is reachable at message time is controlled by the agent's `liveMemory` config flag: when `true`, the per-spawn allowlist includes `memory-search` and reads run with `ALLOWED_SCOPES=public`; when `false`, the agent has no graph access mid-turn. When `liveMemory` is false and the visitor sent no attachment, the public allowlist resolves empty; because public webchat runs in `dontAsk` (Task 506), the spawner anchors the allowlist with a single non-native deny-basis token (`mcp__none__deny-basis`) so `--allowed-tools` is always present and native-excluding (Task 609) — without it, `dontAsk` would have nothing to deny against and the brand `allow:["*"]` would re-open native tools.
226
+ The public agent is toolless by construction (Task 615): it has no `memory-search`, no graph access mid-turn, and no tools of any kind. KNOWLEDGE.md (when present) plus SOUL are assembled into the agent's system prompt at spawn time and are the entire knowledge surface. Every `role=public` spawn (webchat, whatsapp, telegram) resolves an empty allowlist and runs in `dontAsk` (Task 506) with a per-spawn `permissions.deny` covering every native, harness, and memory-MCP tool (Task 612). The spawner anchors the empty allowlist with a single non-native deny-basis token (`mcp__none__deny-basis`) so `--allowed-tools` is always present and native-excluding (Task 609) — without it, `dontAsk` would have nothing to deny against and the brand `allow:["*"]` would re-open native tools.
227
227
 
228
228
  ### Observability
229
229
 
@@ -340,10 +340,7 @@ The final step in the retrieval pipeline is injecting retrieved content into the
340
340
 
341
341
  Public agents run on the same native Claude Code PTY surface as the admin, dispatched through the channel PTY-bridge with `role: 'public'`. The agent's directory files (IDENTITY.md, SOUL.md, KNOWLEDGE.md, KNOWLEDGE-SUMMARY.md when present) are assembled into the system prompt at spawn time. There is no per-turn server-side knowledge injection.
342
342
 
343
- Two paths, selected by the agent's `liveMemory` config flag:
344
-
345
- - **`liveMemory: false`** — `memory-search` is excluded from the per-spawn `--allowed-tools` allowlist. The agent has no graph access mid-conversation; KNOWLEDGE.md is the ceiling of factual knowledge.
346
- - **`liveMemory: true`** — `memory-search` is in the allowlist. The agent decides at message time whether to call it; reads run against the graph with `ALLOWED_SCOPES=public` so only public-scoped nodes return. KNOWLEDGE.md and the live `memory-search` surface are complementary — the baked file covers evergreen facts; the live tool covers the long-tail public-scoped lookups.
343
+ The public agent is toolless by construction (Task 615): `memory-search` and every other tool are excluded from the per-spawn `--allowed-tools` allowlist on every public channel, and a per-spawn `permissions.deny` blocks them outright (Task 612). The agent has no graph access mid-conversation; KNOWLEDGE.md is the ceiling of factual knowledge.
347
344
 
348
345
  ### KNOWLEDGE.md staleness guard
349
346
 
@@ -447,7 +444,7 @@ The SDK's per-tool override is `_meta["anthropic/alwaysLoad"]: true` on each MCP
447
444
 
448
445
  Each `claude` PTY spawn registers every callable MCP server and every dispatchable subagent before the operator's first turn. **Platform MCP servers come from one channel — installed plugins — for admin and specialist spawns (Task 502).** Claude Code's plugin system serves every plugin MCP tool under the long prefix `mcp__plugin_<plugin>_<server>__<tool>` (for platform plugins `plugin == server == directory`), which is the canonical name the admin `--allowed-tools` argv and every specialist `tools:` frontmatter bind to. Admin spawns no longer write a per-spawn `.mcp.json` or pass `--mcp-config`; the per-account env (`ACCOUNT_ID`, `USER_ID`, `NEO4J_URI`, `NEO4J_PASSWORD`, `PLATFORM_ROOT`, `CLAUDE_CONFIG_DIR`) rides the PTY env block.
449
446
 
450
- **Public agents are the one exception.** A public-facing web agent should boot only the handful of servers it may use, not every installed plugin, so public spawns retain the per-spawn `mcp-config.json` (`--mcp-config <path>`) that restricts the server set to plugins exposing at least one `publicAllowlist: true` tool (minus memory when `liveMemory: false`). Per-spawn descriptors keep the SHORT prefix `mcp__<plugin>__<tool>`, which is why the public allowlist (`toolSurface.public`) stays short while admin/all are long. The descriptor's `command` routes through `lib/mcp-spawn-tee/dist/index.js` so each child server's stderr lands in `${LOG_DIR}/mcp-<name>-stderr-<date>.log` even on synchronous module-load throws (Task 743 wrapper). `--strict-mcp-config` only ever guarded auto-discovery of a project `.mcp.json`; it is retained on the public per-spawn path and dropped from admin spawns that no longer pass `--mcp-config`.
447
+ **Public agents are the one exception.** A public-facing web agent is toolless by construction (Task 615), so public spawns retain the per-spawn `mcp-config.json` (`--mcp-config <path>`) but register **zero** servers in it the file carries an empty `mcpServers`. Combined with the empty `--allowed-tools`, the `dontAsk` mode, and the per-spawn `permissions.deny` (Task 612), no tool reaches an anonymous visitor on any channel. `--strict-mcp-config` (which only ever guarded auto-discovery of a project `.mcp.json`) is retained on the public per-spawn path so no project file is discovered either; it is dropped from admin spawns that no longer pass `--mcp-config`.
451
448
 
452
449
  For subagents, the same spawn pushes `--add-dir` for every bundled plugin agents directory (`platform/plugins/*/agents/`, `premium-plugins/*/agents/`) — both roles — plus the per-account specialists directory `<accountDir>/specialists/agents/` (admin only). Claude Code's `subagent_type` dispatch reads the agent file off disk via the added directories; without `--add-dir` the dispatcher returns "no matching agent."
453
450
 
@@ -3,7 +3,7 @@ name: memory
3
3
  description: "Graph memory plugin. Provides memory-search (with optional `fields` projection for known-shape lookups), memory-write, memory-update, memory-edge (create/delete typed directed edges between pre-existing nodes), memory-update-by-name (repair surface that resolves an elementId from a (label, name, accountId) tuple when search cannot return one), memory-lookup-by-name (deterministic read surface that returns nodes by case-insensitive exact `name` match, optionally constrained by labels, bypassing the memory-search ranking stack so a present entity is never missed because a diluted query ranked it below the cut), and the :Report surface (memory-report-write / memory-report-read-latest / memory-report-list) for reading from, writing to, and updating the Neo4j knowledge graph. Includes conversational memory — organic preference learning, evidence-backed recall, and transparent 'what do you know about me?' responses. Document ingestion goes through memory-ingest; the dispatched specialist produces typed-section JSON in-turn from the loaded ontology. Operator-solicited reclassify of an already-stored thread-shaped KD (today: email-thread KDs) is exposed as `kd-classify <attachmentId>` — runs a body-growth gate (proceed iff body grew ≥25% since the last classify, or first-ever classify), stages the body to a temp file under `$ACCOUNT_DIR/tmp/`, and returns a dispatch envelope for the `librarian`; on success `memory-ingest` replaces the prior :Section children and stamps `lastClassifiedAt` + `lastClassifiedBodyLength` on the parent KD. Two modes: `document` (default) for unstructured PDF/web content → :KnowledgeDocument (keyed on `attachmentId`) + :Section, and `chat` for conversation transcripts → :ConversationArchive (keyed on `conversationIdentity`) + :Section chunks; two parent labels, two writer paths chosen by which identity property is set. Conversation-archive Phase 2 splits across two read-only tools (Task 433): `conversation-archive-list-chunks` pages chunk bodies for the dispatched specialist to read in-turn; `conversation-archive-derive-insights` converts the specialist's per-chunk claims into operator-facing proposals with per-kind cypher. `conversation-archive-enrich-rejection` records (or undoes) durable per-row rejections so already-triaged claims do not re-surface on re-runs. Ships five skills: `conversational-memory`, `document-ingest`, `conversation-archive` (source-agnostic transcript ingest for WhatsApp, Telegram, Signal, LinkedIn DMs, Zoom, meeting minutes, iMessage, Slack), `conversation-archive-mcp` (operator-initiated MCP-driven ingest for Granola, Otter, Circleback meetings — sibling of `conversation-archive` sharing the same writer surface and identity formula), and `conversation-archive-enrich` (per-row operator-gated insight derivation over a named archive's chunks). Ships three thinking-tool skills: `challenge` (adversarial retrieval — strongest counter-evidence from the graph for a given claim), `connect` (bridge-finding between two topics via shared graph neighbors), and `emerge` (clusters uncategorised KnowledgeDocument and Section nodes into operator-approved Concept proposals)."
4
4
  tools:
5
5
  - name: memory-search
6
- publicAllowlist: true
6
+ publicAllowlist: false
7
7
  adminAllowlist: true
8
8
  - name: memory-write
9
9
  publicAllowlist: false
@@ -161,7 +161,7 @@ mcp-manifest: auto
161
161
 
162
162
  # Memory
163
163
 
164
- Provides read and write access to the Neo4j knowledge graph — search, structured writes, document ingestion, attachment management, conversation history, and user profiles. Tool routing is each agent's IDENTITY.md responsibility; this plugin describes what tools are available, not when to use them. The admin agent and specialist subagents call these tools directly via MCP. Public agents with `liveMemory: true` in their config receive `memory-search` via the per-spawn `--allowed-tools` allowlist; the memory MCP server scopes every read to `ALLOWED_SCOPES=public` so only nodes with `scope: "public"` are reachable. Public agents with `liveMemory: false` get no MCP tools from this plugin — their knowledge comes only from the baked KNOWLEDGE.md.
164
+ Provides read and write access to the Neo4j knowledge graph — search, structured writes, document ingestion, attachment management, conversation history, and user profiles. Tool routing is each agent's IDENTITY.md responsibility; this plugin describes what tools are available, not when to use them. The admin agent and specialist subagents call these tools directly via MCP. Public agents are toolless by construction (Task 615): they receive no MCP tools from this plugin and have no graph access mid-conversation — their knowledge comes only from the baked KNOWLEDGE.md and SOUL assembled into the system prompt at spawn.
165
165
 
166
166
  Tools are available via the `memory` MCP server.
167
167