@rubytech/create-maxy 1.0.623 → 1.0.624
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/package.json +1 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js +1 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/skills/onboarding/SKILL.md +9 -12
- package/payload/platform/plugins/cloudflare/PLUGIN.md +31 -44
- package/payload/platform/plugins/cloudflare/mcp/dist/index.js +13 -875
- package/payload/platform/plugins/cloudflare/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.d.ts.map +1 -1
- package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.js +1 -0
- package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.js.map +1 -1
- package/payload/platform/plugins/cloudflare/references/dashboard-guide.md +108 -0
- package/payload/platform/plugins/cloudflare/references/manual-setup.md +445 -0
- package/payload/platform/plugins/cloudflare/references/reset-guide.md +118 -0
- package/payload/platform/plugins/cloudflare/scripts/reset-tunnel.sh +65 -0
- package/payload/platform/plugins/cloudflare/scripts/setup-tunnel.sh +244 -0
- package/payload/platform/plugins/cloudflare/skills/setup-tunnel/SKILL.md +96 -5
- package/payload/platform/plugins/docs/references/cloudflare.md +91 -34
- package/payload/platform/templates/agents/admin/IDENTITY.md +10 -4
- package/payload/platform/templates/specialists/agents/personal-assistant.md +9 -9
- package/payload/server/server.js +187 -299
- package/payload/platform/config/cloudflared.yml +0 -17
- package/payload/platform/plugins/cloudflare/references/setup-guide.md +0 -132
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Deterministic Cloudflare tunnel setup — mirrors
|
|
3
|
+
# platform/plugins/cloudflare/references/manual-setup.md step-by-step.
|
|
4
|
+
# Brand-scoped paths, user-space systemd, apex-aware.
|
|
5
|
+
#
|
|
6
|
+
# Usage:
|
|
7
|
+
# setup-tunnel.sh <brand> <port> <hostname> [<hostname> ...]
|
|
8
|
+
#
|
|
9
|
+
# Example:
|
|
10
|
+
# setup-tunnel.sh maxy 19200 admin.maxy.bot public.maxy.bot maxy.chat
|
|
11
|
+
#
|
|
12
|
+
# Apex hostnames (exactly two DNS labels) cannot have their CNAMEs created
|
|
13
|
+
# via `cloudflared tunnel route dns` — see manual-setup.md §Step 4 Apex
|
|
14
|
+
# hostnames. The script writes the ingress rule for them but prints an
|
|
15
|
+
# explicit ACTION REQUIRED message naming the manual dashboard step.
|
|
16
|
+
|
|
17
|
+
set -euo pipefail
|
|
18
|
+
|
|
19
|
+
# --------------------------------------------------------------------------
|
|
20
|
+
# Args
|
|
21
|
+
# --------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
if [ "$#" -lt 3 ]; then
|
|
24
|
+
echo "Usage: $0 <brand> <port> <hostname> [<hostname> ...]" >&2
|
|
25
|
+
echo "Example: $0 maxy 19200 admin.maxy.bot public.maxy.bot maxy.chat" >&2
|
|
26
|
+
exit 2
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
BRAND="$1"
|
|
30
|
+
PORT="$2"
|
|
31
|
+
shift 2
|
|
32
|
+
HOSTNAMES=("$@")
|
|
33
|
+
|
|
34
|
+
# --------------------------------------------------------------------------
|
|
35
|
+
# Step 0: Set brand context (paths + dirs). Corresponds to runbook Step 0.
|
|
36
|
+
# --------------------------------------------------------------------------
|
|
37
|
+
|
|
38
|
+
CFG_DIR="${HOME}/.${BRAND}/cloudflared"
|
|
39
|
+
mkdir -p "${CFG_DIR}"
|
|
40
|
+
|
|
41
|
+
# --------------------------------------------------------------------------
|
|
42
|
+
# Step 1: OAuth login (only if cert.pem missing). Corresponds to runbook Step 1.
|
|
43
|
+
# cloudflared always writes cert.pem to ~/.cloudflared/cert.pem regardless
|
|
44
|
+
# of --origincert — mv it into the brand-scoped path on fresh login.
|
|
45
|
+
# --------------------------------------------------------------------------
|
|
46
|
+
|
|
47
|
+
if [ ! -f "${CFG_DIR}/cert.pem" ]; then
|
|
48
|
+
echo "No cert.pem at ${CFG_DIR}/cert.pem — starting OAuth login (DISPLAY=${DISPLAY:-:99})"
|
|
49
|
+
DISPLAY="${DISPLAY:-:99}" cloudflared --origincert "${CFG_DIR}/cert.pem" tunnel login &
|
|
50
|
+
LOGIN_PID=$!
|
|
51
|
+
# cloudflared login writes to ~/.cloudflared/cert.pem regardless of --origincert
|
|
52
|
+
while [ ! -f "${HOME}/.cloudflared/cert.pem" ]; do
|
|
53
|
+
if ! kill -0 "${LOGIN_PID}" 2>/dev/null; then
|
|
54
|
+
echo "ERROR: cloudflared tunnel login exited before cert.pem landed" >&2
|
|
55
|
+
exit 1
|
|
56
|
+
fi
|
|
57
|
+
sleep 2
|
|
58
|
+
done
|
|
59
|
+
mv "${HOME}/.cloudflared/cert.pem" "${CFG_DIR}/cert.pem"
|
|
60
|
+
echo "cert.pem moved to ${CFG_DIR}/cert.pem"
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
# --------------------------------------------------------------------------
|
|
64
|
+
# Step 2+3: Create tunnel if absent; otherwise reuse. Capture UUID.
|
|
65
|
+
# --------------------------------------------------------------------------
|
|
66
|
+
|
|
67
|
+
TUNNEL_NAME="${BRAND}-$(hostname -s)"
|
|
68
|
+
TUNNEL_ID="$(cloudflared --origincert "${CFG_DIR}/cert.pem" tunnel list --output json 2>/dev/null \
|
|
69
|
+
| jq -r --arg N "${TUNNEL_NAME}" '.[]? | select(.name == $N) | .id' | head -1)"
|
|
70
|
+
if [ -z "${TUNNEL_ID}" ] || [ "${TUNNEL_ID}" = "null" ]; then
|
|
71
|
+
cloudflared --origincert "${CFG_DIR}/cert.pem" tunnel create "${TUNNEL_NAME}"
|
|
72
|
+
TUNNEL_ID="$(cloudflared --origincert "${CFG_DIR}/cert.pem" tunnel list --output json \
|
|
73
|
+
| jq -r --arg N "${TUNNEL_NAME}" '.[]? | select(.name == $N) | .id' | head -1)"
|
|
74
|
+
fi
|
|
75
|
+
if [ -z "${TUNNEL_ID}" ] || [ "${TUNNEL_ID}" = "null" ]; then
|
|
76
|
+
echo "ERROR: failed to create or find tunnel ${TUNNEL_NAME}" >&2
|
|
77
|
+
exit 1
|
|
78
|
+
fi
|
|
79
|
+
echo "tunnel: ${TUNNEL_NAME} (${TUNNEL_ID})"
|
|
80
|
+
|
|
81
|
+
# --------------------------------------------------------------------------
|
|
82
|
+
# Step 4: Route DNS. Apex hostnames (exactly two DNS labels) cannot be
|
|
83
|
+
# routed via `cloudflared tunnel route dns` — it misroutes them into
|
|
84
|
+
# another zone on the account. Skip CLI routing for apex; collect for the
|
|
85
|
+
# ACTION REQUIRED summary at the end.
|
|
86
|
+
# --------------------------------------------------------------------------
|
|
87
|
+
|
|
88
|
+
is_apex() {
|
|
89
|
+
local h="$1"
|
|
90
|
+
# Apex heuristic: exactly one dot (e.g. maxy.chat). Breaks for
|
|
91
|
+
# multi-label public suffixes like .co.uk; refine if needed.
|
|
92
|
+
[ "$(echo -n "$h" | tr -cd '.' | wc -c)" = "1" ]
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
APEX_HOSTNAMES=()
|
|
96
|
+
for H in "${HOSTNAMES[@]}"; do
|
|
97
|
+
if is_apex "$H"; then
|
|
98
|
+
APEX_HOSTNAMES+=("$H")
|
|
99
|
+
echo "apex ${H} — skipping CLI DNS routing (manual dashboard step required)"
|
|
100
|
+
continue
|
|
101
|
+
fi
|
|
102
|
+
ROUTE_OUT=$(cloudflared --origincert "${CFG_DIR}/cert.pem" \
|
|
103
|
+
tunnel route dns --overwrite-dns "${TUNNEL_ID}" "${H}" 2>&1)
|
|
104
|
+
echo "${ROUTE_OUT}"
|
|
105
|
+
# Post-flight FQDN validation: cert.pem is zone-scoped for DNS routing;
|
|
106
|
+
# if the requested hostname is not under cert's zone, cloudflared silently
|
|
107
|
+
# prepends it as a sub-label (e.g. admin.maxy.bot → admin.maxy.bot.maxy.chat
|
|
108
|
+
# when cert is for maxy.chat zone). Parse the output and fail loudly.
|
|
109
|
+
ACTUAL_FQDN=$(echo "${ROUTE_OUT}" | sed -n 's|.*Added CNAME \([^ ]*\) which will route.*|\1|p')
|
|
110
|
+
if [ -z "${ACTUAL_FQDN}" ]; then
|
|
111
|
+
echo "ERROR: could not parse CNAME FQDN from cloudflared output for ${H}" >&2
|
|
112
|
+
exit 1
|
|
113
|
+
fi
|
|
114
|
+
if [ "${ACTUAL_FQDN}" != "${H}" ]; then
|
|
115
|
+
echo "" >&2
|
|
116
|
+
echo "ERROR: cloudflared misrouted ${H} → ${ACTUAL_FQDN}" >&2
|
|
117
|
+
echo " The cert.pem at ${CFG_DIR}/cert.pem is scoped to a zone that does not own ${H}." >&2
|
|
118
|
+
echo " Fix:" >&2
|
|
119
|
+
echo " 1. Delete the stray CNAME ${ACTUAL_FQDN} in the CF dashboard." >&2
|
|
120
|
+
echo " 2. Re-authorize cloudflared against the zone that owns ${H}:" >&2
|
|
121
|
+
echo " rm ${CFG_DIR}/cert.pem" >&2
|
|
122
|
+
echo " DISPLAY=:99 cloudflared --origincert ${CFG_DIR}/cert.pem tunnel login" >&2
|
|
123
|
+
echo " (then pick the correct zone in the dashboard consent screen)" >&2
|
|
124
|
+
echo " mv ~/.cloudflared/cert.pem ${CFG_DIR}/cert.pem" >&2
|
|
125
|
+
echo " 3. Re-run this script." >&2
|
|
126
|
+
exit 1
|
|
127
|
+
fi
|
|
128
|
+
done
|
|
129
|
+
|
|
130
|
+
# --------------------------------------------------------------------------
|
|
131
|
+
# Step 5: Write config.yml. Every hostname (apex + subdomain) gets an
|
|
132
|
+
# ingress rule — apex still needs the rule for the connector to serve
|
|
133
|
+
# traffic once DNS is manually pointed.
|
|
134
|
+
# --------------------------------------------------------------------------
|
|
135
|
+
|
|
136
|
+
{
|
|
137
|
+
echo "tunnel: ${TUNNEL_ID}"
|
|
138
|
+
echo "credentials-file: ${CFG_DIR}/${TUNNEL_ID}.json"
|
|
139
|
+
echo "ingress:"
|
|
140
|
+
for H in "${HOSTNAMES[@]}"; do
|
|
141
|
+
echo " - hostname: ${H}"
|
|
142
|
+
echo " service: http://localhost:${PORT}"
|
|
143
|
+
done
|
|
144
|
+
echo " - service: http_status:404"
|
|
145
|
+
} > "${CFG_DIR}/config.yml"
|
|
146
|
+
echo "wrote ${CFG_DIR}/config.yml"
|
|
147
|
+
|
|
148
|
+
# --------------------------------------------------------------------------
|
|
149
|
+
# Step 5b: Write tunnel.state. Required by resume-tunnel.sh — without it
|
|
150
|
+
# the brand.service's ExecStartPre exits silently without spawning a
|
|
151
|
+
# connector.
|
|
152
|
+
# --------------------------------------------------------------------------
|
|
153
|
+
|
|
154
|
+
cat > "${CFG_DIR}/tunnel.state" <<EOF
|
|
155
|
+
{
|
|
156
|
+
"tunnelId": "${TUNNEL_ID}",
|
|
157
|
+
"tunnelName": "${TUNNEL_NAME}",
|
|
158
|
+
"domain": "${HOSTNAMES[0]}",
|
|
159
|
+
"configPath": "${CFG_DIR}/config.yml",
|
|
160
|
+
"credentialsPath": "${CFG_DIR}/${TUNNEL_ID}.json"
|
|
161
|
+
}
|
|
162
|
+
EOF
|
|
163
|
+
echo "wrote ${CFG_DIR}/tunnel.state"
|
|
164
|
+
|
|
165
|
+
# --------------------------------------------------------------------------
|
|
166
|
+
# Restart the brand's user-space service so resume-tunnel.sh (its
|
|
167
|
+
# ExecStartPre) picks up the new tunnel.state + config.yml and spawns the
|
|
168
|
+
# connector. The script is autonomous — it completes the deployment.
|
|
169
|
+
# --------------------------------------------------------------------------
|
|
170
|
+
|
|
171
|
+
if ! systemctl --user list-unit-files "${BRAND}.service" --no-pager --no-legend | grep -q "${BRAND}.service"; then
|
|
172
|
+
echo "ERROR: user-space service ${BRAND}.service not installed — cannot bring the tunnel up" >&2
|
|
173
|
+
echo " Install the platform first (create-maxy) before running this script." >&2
|
|
174
|
+
exit 1
|
|
175
|
+
fi
|
|
176
|
+
|
|
177
|
+
echo "Restarting ${BRAND}.service to spawn the connector with the new tunnel state..."
|
|
178
|
+
systemctl --user restart "${BRAND}.service"
|
|
179
|
+
|
|
180
|
+
# Give resume-tunnel.sh a moment to spawn the connector before probing.
|
|
181
|
+
sleep 3
|
|
182
|
+
|
|
183
|
+
# --------------------------------------------------------------------------
|
|
184
|
+
# Post-restart verification — connector running and subdomains live?
|
|
185
|
+
# Poll each hostname up to VERIFY_TIMEOUT seconds so DNS propagation has
|
|
186
|
+
# time to catch up (subdomains routed by cloudflared typically resolve
|
|
187
|
+
# within 10-30s; apex-flattened or freshly-created records may need longer).
|
|
188
|
+
# --------------------------------------------------------------------------
|
|
189
|
+
|
|
190
|
+
if ! ps -ef | grep -q "[c]loudflared.*--config ${CFG_DIR}/config.yml"; then
|
|
191
|
+
echo "" >&2
|
|
192
|
+
echo "ERROR: ${BRAND}.service restarted but no cloudflared connector is running" >&2
|
|
193
|
+
echo " with --config ${CFG_DIR}/config.yml." >&2
|
|
194
|
+
echo " Check ${HOME}/.${BRAND}/logs/cloudflared.log for the failure reason." >&2
|
|
195
|
+
exit 1
|
|
196
|
+
fi
|
|
197
|
+
|
|
198
|
+
VERIFY_TIMEOUT=60
|
|
199
|
+
POLL_INTERVAL=5
|
|
200
|
+
echo "Connector running against ${CFG_DIR}/config.yml — verifying each subdomain hostname (up to ${VERIFY_TIMEOUT}s per host for DNS propagation):"
|
|
201
|
+
for H in "${HOSTNAMES[@]}"; do
|
|
202
|
+
if is_apex "$H"; then continue; fi
|
|
203
|
+
ELAPSED=0
|
|
204
|
+
STATUS="000"
|
|
205
|
+
while [ "${ELAPSED}" -lt "${VERIFY_TIMEOUT}" ]; do
|
|
206
|
+
STATUS=$(curl -o /dev/null -s -w '%{http_code}' --max-time 5 -I "https://${H}" || echo "000")
|
|
207
|
+
if [ "${STATUS}" != "530" ] && [ "${STATUS}" != "000" ]; then
|
|
208
|
+
break
|
|
209
|
+
fi
|
|
210
|
+
sleep "${POLL_INTERVAL}"
|
|
211
|
+
ELAPSED=$((ELAPSED + POLL_INTERVAL))
|
|
212
|
+
done
|
|
213
|
+
if [ "${STATUS}" = "530" ] || [ "${STATUS}" = "000" ]; then
|
|
214
|
+
echo " ${H}: HTTP ${STATUS} after ${VERIFY_TIMEOUT}s — DNS propagation slow or connector-to-edge issue"
|
|
215
|
+
else
|
|
216
|
+
echo " ${H}: HTTP ${STATUS} — live (after ${ELAPSED}s)"
|
|
217
|
+
fi
|
|
218
|
+
done
|
|
219
|
+
|
|
220
|
+
# --------------------------------------------------------------------------
|
|
221
|
+
# Apex ACTION REQUIRED summary
|
|
222
|
+
# --------------------------------------------------------------------------
|
|
223
|
+
|
|
224
|
+
if [ "${#APEX_HOSTNAMES[@]}" -gt 0 ]; then
|
|
225
|
+
echo ""
|
|
226
|
+
echo "============================================================"
|
|
227
|
+
echo "ACTION REQUIRED — manual dashboard step(s) for apex hostnames"
|
|
228
|
+
echo "============================================================"
|
|
229
|
+
for H in "${APEX_HOSTNAMES[@]}"; do
|
|
230
|
+
echo " ${H}"
|
|
231
|
+
echo " Cloudflare dashboard → ${H} zone → DNS → Records"
|
|
232
|
+
echo " Edit (or Add) CNAME record:"
|
|
233
|
+
echo " Name: @ (zone apex)"
|
|
234
|
+
echo " Content: ${TUNNEL_ID}.cfargotunnel.com"
|
|
235
|
+
echo " Proxy: Proxied (orange cloud)"
|
|
236
|
+
echo ""
|
|
237
|
+
done
|
|
238
|
+
echo "Until each apex record is set, those hostnames will return 1033."
|
|
239
|
+
echo "============================================================"
|
|
240
|
+
fi
|
|
241
|
+
|
|
242
|
+
echo ""
|
|
243
|
+
echo "Done. tunnel=${TUNNEL_NAME} id=${TUNNEL_ID}"
|
|
244
|
+
echo "Verify subdomain hostnames with: curl -I https://${HOSTNAMES[0]}"
|
|
@@ -1,12 +1,103 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: setup-tunnel
|
|
3
|
-
description:
|
|
3
|
+
description: Cloudflare Tunnel operations — setup, diagnose, reset, dashboard guidance. Every path runs through one of four sanctioned surfaces; the agent never improvises outside them.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# Cloudflare operations
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Every Cloudflare task — setup, diagnosis, reset, DNS edit — lands on exactly one of four sanctioned surfaces. The agent's job is to pick the right surface, collect the inputs it needs, invoke it, and relay the structured result verbatim.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
There are no Cloudflare MCP tools. The plugin registers none. The only agent-facing surfaces for Cloudflare work are:
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
1. **Autonomous path** — run `setup-tunnel.sh` via the Bash tool.
|
|
13
|
+
2. **Manual fallback** — quote steps from `references/manual-setup.md`.
|
|
14
|
+
3. **Reset path** — run `reset-tunnel.sh` via Bash, then follow `references/reset-guide.md`.
|
|
15
|
+
4. **Dashboard guidance** — relay click-paths from `references/dashboard-guide.md`.
|
|
16
|
+
|
|
17
|
+
Any Cloudflare action outside these four surfaces is a discipline violation — see § Tool discipline below.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 1. Autonomous path — `setup-tunnel.sh`
|
|
22
|
+
|
|
23
|
+
Use this when the operator wants Cloudflare set up (or re-set up) end-to-end on the device. The script handles OAuth login, tunnel creation, DNS routing for each subdomain, config.yml + tunnel.state, service restart, and post-restart verification — all in one invocation. Apex hostnames cannot be routed by the CLI; when one is passed, the script prints an `ACTION REQUIRED` block naming the exact dashboard record to edit.
|
|
24
|
+
|
|
25
|
+
### Inputs to collect before invoking
|
|
26
|
+
|
|
27
|
+
Ask the operator each question once. Do not invoke the script until every required input is in hand.
|
|
28
|
+
|
|
29
|
+
| Input | Example | Required? | How to ask |
|
|
30
|
+
|---|---|---|---|
|
|
31
|
+
| Brand | `maxy`, `realagent` | yes | Usually known from the device context (`brand.json`). Confirm if ambiguous. |
|
|
32
|
+
| Platform port | `19200` (maxy), `19500` (realagent) | yes | Known from brand. Do not ask the operator. |
|
|
33
|
+
| Admin hostname | `admin.maxy.bot`, `joel.example.com` | yes | "What hostname should serve the admin chat?" |
|
|
34
|
+
| Public hostname | `public.maxy.bot`, `chat.example.com` | optional | "Any hostname for the public agent? Say no to skip." |
|
|
35
|
+
| Apex hostname | `maxy.chat`, `example.com` | optional | "Any bare-domain hostname (no subdomain) that should also serve the public agent?" |
|
|
36
|
+
|
|
37
|
+
### Invocation
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
~/setup-tunnel.sh <brand> <port> <admin-hostname> [<public-hostname>] [<apex-hostname>]
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Example (Maxy on `maxy.bot` with a public subdomain and the `maxy.chat` apex):
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
~/setup-tunnel.sh maxy 19200 admin.maxy.bot public.maxy.bot maxy.chat
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Invoke via Bash. When the script exits, relay its output verbatim. If an `ACTION REQUIRED` block appears, quote it exactly — the operator needs the specific dashboard instructions it contains.
|
|
50
|
+
|
|
51
|
+
### When the script exits non-zero
|
|
52
|
+
|
|
53
|
+
Report the failure, name the exit code, and cite `references/reset-guide.md` for the next action. Do not attempt a second invocation, a Playwright-driven dashboard inspection, or an alternative `cloudflared` command sequence. The discipline rule below applies.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 2. Manual fallback — `references/manual-setup.md`
|
|
58
|
+
|
|
59
|
+
Use this when the operator is diagnosing a step that is failing under the script, recovering from a partial state the script does not expect, or working on a device where the scripts are not yet deployed. The runbook covers Steps 0 through 7 with isolated command blocks, success conditions, and troubleshooting per step.
|
|
60
|
+
|
|
61
|
+
The agent's role in manual mode is to read the relevant step, quote the commands the operator runs, and relay their output back through the runbook's decision tree. Do not paraphrase the commands — the operator pastes them verbatim.
|
|
62
|
+
|
|
63
|
+
Cross-reference: every scripted step in `setup-tunnel.sh` mirrors a numbered step in `references/manual-setup.md`, so an operator debugging a script failure can pick up exactly where the script left off.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## 3. Reset path — `reset-tunnel.sh` + `references/reset-guide.md`
|
|
68
|
+
|
|
69
|
+
Use this when the local Cloudflare state is corrupt, the operator wants a fresh start on a known-good cert, or the bound account has been scrubbed or rotated. `reset-tunnel.sh` deletes every tunnel on the brand's Cloudflare account and wipes `${CFG_DIR}`.
|
|
70
|
+
|
|
71
|
+
### Invocation
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
~/reset-tunnel.sh <brand>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Example:
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
~/reset-tunnel.sh maxy
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`reset-tunnel.sh` cannot stop a token-mode connector process or delete stray misrouted CNAMEs in the dashboard. `references/reset-guide.md` names the decision tree (reset vs. patch), the exact `pkill` incantation for token-mode connectors, and the dashboard cleanup paths for stray records.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## 4. Dashboard guidance — `references/dashboard-guide.md`
|
|
88
|
+
|
|
89
|
+
Use this when the operator needs to do something only the Cloudflare dashboard can do: sign in, switch accounts, add a site, edit an apex CNAME, verify zone nameservers, delete a tunnel after stopping its replicas. The guide has one numbered click-path per operation. Quote the relevant click-path verbatim — the operator follows it in the browser; no agent browser automation is involved.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Tool discipline — binding
|
|
94
|
+
|
|
95
|
+
When the operator's request touches Cloudflare, the agent's permitted actions are exactly:
|
|
96
|
+
|
|
97
|
+
- Invoke `setup-tunnel.sh` or `reset-tunnel.sh` via Bash.
|
|
98
|
+
- Quote `references/manual-setup.md`, `references/reset-guide.md`, or `references/dashboard-guide.md`.
|
|
99
|
+
- Verify reachability via plain HTTP (`curl -I https://<hostname>`).
|
|
100
|
+
|
|
101
|
+
The agent does not drive Cloudflare's dashboard via Playwright or Chrome DevTools. The agent does not synthesise `cloudflared` flag combinations from web search or prior training. The agent does not call Cloudflare API or SDK from any language. The agent does not write or mutate `cert.pem`, `tunnel.state`, `config.yml`, or `alias-domains.json` directly — `setup-tunnel.sh` and the operator manage those files.
|
|
102
|
+
|
|
103
|
+
When a sanctioned surface fails, the agent reports the failure with the exact output, cites the recovery step from `references/reset-guide.md`, and stops. Improvisation — "let me try a different flag" or "let me check the dashboard myself" — is the behaviour this rule exists to prevent. See IDENTITY.md § Cloudflare operations for the unconditional form.
|
|
@@ -1,49 +1,106 @@
|
|
|
1
1
|
# Cloudflare Tunnel — the dashboard is the source of truth
|
|
2
2
|
|
|
3
|
-
Each installation has its own Cloudflare account.
|
|
3
|
+
Each installation has its own Cloudflare account. Sign-in is OAuth in the device's VNC browser; `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.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Identity model
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
| Fact | Source |
|
|
7
|
+
| Concept | Source |
|
|
10
8
|
|------|--------|
|
|
11
9
|
| **Product identity** (Maxy vs Real Agent) | `brand.json` (`productName`, `configDir`) — known at install. |
|
|
12
|
-
| **Cloudflare account identity** | `cert.pem` from OAuth
|
|
13
|
-
| **
|
|
10
|
+
| **Cloudflare account identity** | `cert.pem` from OAuth. One account per brand per device. |
|
|
11
|
+
| **Local tunnel state** | `~/{configDir}/cloudflared/` — `cert.pem`, `<UUID>.json`, `config.yml`, `tunnel.state`, `alias-domains.json`. |
|
|
12
|
+
|
|
13
|
+
There is no token-based auth for the operator-owned path (Mode A). To switch Cloudflare accounts, run `reset-tunnel.sh` (which deletes the cert and every tunnel on the current account), then run `setup-tunnel.sh` again — `cloudflared tunnel login` inside the setup script will pick a fresh account when you sign in.
|
|
14
|
+
|
|
15
|
+
## Setup flow
|
|
16
|
+
|
|
17
|
+
Ask the agent to set up Cloudflare. The agent collects four things before acting:
|
|
18
|
+
|
|
19
|
+
1. The admin hostname for this device (e.g. `admin.yourdomain.com`).
|
|
20
|
+
2. Optionally, a public hostname (e.g. `public.yourdomain.com`) for the public agent.
|
|
21
|
+
3. Optionally, an apex hostname (e.g. `yourdomain.com`) as a bare root to serve the public agent.
|
|
22
|
+
4. Confirmation the domain is already on your Cloudflare account (or guidance to add it first — see below).
|
|
23
|
+
|
|
24
|
+
The agent then invokes `setup-tunnel.sh` on the device with your inputs. The script runs end-to-end:
|
|
25
|
+
|
|
26
|
+
- `cloudflared tunnel login` — OAuth browser sign-in. The VNC browser opens the Cloudflare authorize page; pick the account that owns your domain, click Authorize. `cert.pem` lands.
|
|
27
|
+
- Tunnel creation under the naming convention `{brand}-{hostname}` (e.g. `maxy-neo`).
|
|
28
|
+
- `cloudflared tunnel route dns` for each subdomain hostname. Apex hostnames cannot be routed this way — the script prints an **ACTION REQUIRED** block naming the exact dashboard record to add or edit.
|
|
29
|
+
- `config.yml` and `tunnel.state` written under `${CFG_DIR}`.
|
|
30
|
+
- `systemctl --user restart ${BRAND}.service` — restarts the platform service so the new tunnel spawns via the service's `ExecStartPre=resume-tunnel.sh`.
|
|
31
|
+
- Post-restart verification — `ps -ef | grep '[c]loudflared'` confirms the connector is alive, then `curl -I https://<hostname>` against each subdomain (up to 60 s per host) confirms a non-530 response.
|
|
32
|
+
|
|
33
|
+
When the script exits, the agent relays its output verbatim, including any `ACTION REQUIRED` block.
|
|
34
|
+
|
|
35
|
+
## Getting a domain on Cloudflare
|
|
36
|
+
|
|
37
|
+
The tunnel needs a domain on the Cloudflare account the device will sign into. Two paths, both in your browser:
|
|
38
|
+
|
|
39
|
+
**Option A: Buy a new domain through Cloudflare.** Navigate to cloudflare.com → Domains and buy one. Cloudflare sets everything up.
|
|
40
|
+
|
|
41
|
+
**Option B: Add an existing domain.** In the dashboard: Websites → Add a site. Cloudflare imports the existing DNS records; review them to confirm your website and email entries are preserved. Cloudflare gives you two nameservers; replace the registrar's nameservers with those. Propagation is usually minutes (up to 24 hours); the zone shows **Active** when ready.
|
|
42
|
+
|
|
43
|
+
Existing website traffic continues to work during and after the switch. Only DNS resolution changes owners.
|
|
44
|
+
|
|
45
|
+
## Reset / account switch
|
|
46
|
+
|
|
47
|
+
Ask the agent to reset Cloudflare. The agent invokes `reset-tunnel.sh` on the device:
|
|
48
|
+
|
|
49
|
+
- Deletes every tunnel on the brand's current Cloudflare account (via the bound cert).
|
|
50
|
+
- Wipes the brand's `${CFG_DIR}`.
|
|
51
|
+
- Exits with the number of tunnels deleted.
|
|
52
|
+
|
|
53
|
+
The script does **not** stop token-mode connector processes, delete stray misrouted CNAMEs in the dashboard, or touch the platform service. If any of those apply (agent will flag them), the agent guides you through the manual cleanup — `pkill -f 'cloudflared.*tunnel run --token'` on the device, or deleting the stray CNAME in the dashboard.
|
|
54
|
+
|
|
55
|
+
After reset, run setup again. The fresh `cloudflared tunnel login` will pick whichever Cloudflare account you sign into.
|
|
56
|
+
|
|
57
|
+
## Manual runbook
|
|
58
|
+
|
|
59
|
+
When the scripted flow fails partway, or you want to walk through every step yourself, there's a step-by-step runbook at `plugins/cloudflare/references/manual-setup.md`. The runbook mirrors `setup-tunnel.sh` verbatim — every scripted step corresponds to a numbered runbook step with isolated command blocks, success conditions, and troubleshooting. Pick up the runbook at whichever step the script failed in.
|
|
60
|
+
|
|
61
|
+
## Dashboard operations the CLI cannot do
|
|
62
|
+
|
|
63
|
+
The CLI cannot add a domain, switch accounts, edit an apex CNAME, or delete stray records. `plugins/cloudflare/references/dashboard-guide.md` has one numbered click-path per operation. The agent quotes the relevant steps verbatim when you need to do one of these things.
|
|
64
|
+
|
|
65
|
+
## Troubleshooting
|
|
66
|
+
|
|
67
|
+
### Tunnel won't start
|
|
68
|
+
|
|
69
|
+
Ask the agent to check. The agent reads `systemctl --user status ${BRAND}.service` and `~/{configDir}/cloudflared/logs/cloudflared.log`. Common states:
|
|
70
|
+
|
|
71
|
+
- **No cloudflared process running** — the service's `ExecStartPre=resume-tunnel.sh` exited cleanly but did not spawn the connector. Usually means `tunnel.state` is missing or `config.yml` was written with empty variables. The agent will re-run `setup-tunnel.sh`.
|
|
72
|
+
- **`tunnel not found`** — the UUID in `config.yml` does not match any tunnel on the currently-bound account. Usually follows an account switch that didn't reset local state. The agent invokes `reset-tunnel.sh` and then a fresh setup.
|
|
73
|
+
|
|
74
|
+
### URL returns 530
|
|
75
|
+
|
|
76
|
+
DNS propagation or account mismatch. Wait 30–60 seconds and retry first. If the 530 persists:
|
|
77
|
+
|
|
78
|
+
- The domain may be on a Cloudflare account different from the one `cert.pem` is bound to — re-running `setup-tunnel.sh` re-validates.
|
|
79
|
+
- The UDP buffer for QUIC may be undersized on this device — check `cloudflared.log` for `failed to sufficiently increase receive buffer size`.
|
|
80
|
+
|
|
81
|
+
### URL returns connection refused
|
|
82
|
+
|
|
83
|
+
The tunnel is live but nothing is listening on the platform port. Start the platform service: `systemctl --user start ${BRAND}.service`.
|
|
84
|
+
|
|
85
|
+
### Admin hostname serves the public agent
|
|
86
|
+
|
|
87
|
+
`admin.yourdomain` is being misclassified as public. The platform UI treats a host as public when either (a) the hostname starts with `public.`, or (b) the hostname appears in `${CFG_DIR}/alias-domains.json`. Older install flows wrote every routed hostname into `alias-domains.json`; the pollution survives across reinstalls.
|
|
14
88
|
|
|
15
|
-
|
|
89
|
+
The agent reads `alias-domains.json`, removes the offending `admin.*` entry, and the platform UI hot-reloads — no restart needed. See `plugins/cloudflare/references/reset-guide.md` § "Remove a rogue entry from alias-domains.json" for the exact `jq` command.
|
|
16
90
|
|
|
17
|
-
|
|
91
|
+
### DNS not resolving
|
|
18
92
|
|
|
19
|
-
The
|
|
93
|
+
The most common cause is wrong nameservers on the domain. The domain must use Cloudflare's nameservers, not the registrar's defaults. In the dashboard: Websites → your domain → status must say **Active**, not **Pending**. If Pending, follow the dashboard's nameserver instructions and wait for propagation.
|
|
20
94
|
|
|
21
|
-
|
|
22
|
-
2. Agent calls `cloudflare-setup-run({ domain: "maxy.bot" })`. Tool spawns `cloudflared tunnel login` and returns a device-URL card pointing at the Cloudflare sign-in page. The VNC browser opens the URL automatically (or the agent tells the operator to open it manually when the VNC browser is down).
|
|
23
|
-
3. Operator signs into the Cloudflare account that owns `maxy.bot`, clicks Authorize, says "done" in the chat.
|
|
24
|
-
4. Agent calls `cloudflare-setup-run({ confirmed: true })`. Tool sees the cert landed, asks for admin/public subdomain names.
|
|
25
|
-
5. Operator: "admin and public."
|
|
26
|
-
6. Agent calls `cloudflare-setup-run({ adminSubdomain: "admin", publicSubdomain: "public" })`. Tool creates the tunnel, routes DNS, starts the daemon, and polls `tunnel-status` until `healthy: true` (or a named reason).
|
|
27
|
-
7. Agent relays the final `Tunnel is healthy at https://admin.maxy.bot / https://public.maxy.bot`.
|
|
95
|
+
### Remote login issues
|
|
28
96
|
|
|
29
|
-
|
|
97
|
+
- 5 failed login attempts → 15-minute lockout — wait for expiry.
|
|
98
|
+
- The remote password can be reset by asking the agent on the local network.
|
|
30
99
|
|
|
31
|
-
##
|
|
100
|
+
## What the agent does and does not do
|
|
32
101
|
|
|
33
|
-
|
|
34
|
-
|------|-----|
|
|
35
|
-
| `cloudflare-setup-run` | **The operator-facing entry point.** Runs the full setup flow deterministically. Call with `domain` on the first turn, `adminSubdomain` (+ optional `publicSubdomain`) when the tool asks, and `confirmed: true` when the operator has finished a device-bound step (sign-in, account switch). Safe to call repeatedly — state persists across calls. |
|
|
36
|
-
| `cloudflare-setup-status` | Read-only: what phase is the setup orchestrator in right now? Useful for diagnostics. |
|
|
37
|
-
| `tunnel-login` | Internal sub-tool of the orchestrator. Direct invocation supported for diagnostics. Not available during an active setup — the tool-surface filter removes it from the menu. |
|
|
38
|
-
| `tunnel-install` | Install the `cloudflared` binary. |
|
|
39
|
-
| `tunnel-create` | Create tunnel, route DNS for chosen sub-addresses. Internal sub-tool of the orchestrator (not reachable during active setup). |
|
|
40
|
-
| `tunnel-add-hostname` | Add an alias address **after** the initial setup is complete. Same pre-flight/post-flight refusals as `tunnel-create`. |
|
|
41
|
-
| `tunnel-enable` / `tunnel-disable` | Start / stop the tunnel daemon. `tunnel-enable` is an internal sub-tool of the orchestrator (not reachable during active setup). |
|
|
42
|
-
| `tunnel-status` | Full state including end-to-end probe of every configured address. `healthy: true` requires every address to probe `ok`. `boundAccountOwnsHostnames: false` means the laptop is running a tunnel nothing from the internet is reaching — almost always "signed into the wrong Cloudflare account." Available at all times (the orchestrator consumes its output internally and the enum is useful for direct diagnostic too). |
|
|
43
|
-
| `dns-lookup` | DNS diagnostics against public resolvers. |
|
|
102
|
+
**Does:** invokes `setup-tunnel.sh` / `reset-tunnel.sh` via Bash, quotes click-paths from the reference files verbatim, verifies external reachability with `curl -I`.
|
|
44
103
|
|
|
45
|
-
|
|
104
|
+
**Does not:** drive the Cloudflare dashboard via Playwright, synthesise alternative `cloudflared` flag sequences, call any Cloudflare API or SDK, write or edit `cert.pem` / `tunnel.state` / `config.yml` / `alias-domains.json` directly.
|
|
46
105
|
|
|
47
|
-
|
|
48
|
-
- **Refusal `hostname-zone-not-routable`** → the domain is not on Cloudflare yet, or the laptop is signed into a Cloudflare account that does not own it. Operator opens the dashboard; when the domain has never been added, they add it via Websites → Add a site under the correct account. When the domain is on a different account, they switch to the correct account using the top-left dropdown. Agent then retries.
|
|
49
|
-
- **Refusal `post-flight-fqdn-mismatch` or `bound-account-does-not-own-hostname`** → the laptop is signed into a Cloudflare account that does not own the target domain. `cloudflared` routed the address under a different domain. Operator switches Cloudflare accounts in the browser, agent runs `tunnel-login force=true`, then retries.
|
|
106
|
+
When a script or command fails, the agent reports the failure and cites the relevant recovery step. It does not improvise.
|
|
@@ -58,13 +58,19 @@ Do not retry the same tool against the same target within a turn. A second ident
|
|
|
58
58
|
|
|
59
59
|
When a tool returns a structured failure whose error content begins with an UPPERCASE_ERROR_CODE (for example `WEBFETCH_CANNOT_READ_JS_SPA`), the runtime has already determined that retrying the same tool will fail and that a substitute would launder uncertainty. Read the error's plain-English explanation, then write one or two sentences to the owner that name (a) what failed, (b) the reason in their language, and (c) the concrete actions they can take to unblock — typically pasting text or sending a screenshot. Do not silently dispatch a substitute (Playwright, research-assistant, memory-search) to continue the original instruction; that hides the failure and the owner loses the ability to judge whether the substitute's output answers their question. A verbal instruction in the current conversation is not consent — only an explicit standing policy recorded in account configuration counts, and no such mechanism exists today. Until one exists, every structured tool failure becomes a question for the owner. Wait for direction before resuming.
|
|
60
60
|
|
|
61
|
-
##
|
|
61
|
+
## Cloudflare operations
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
When the operator's request touches Cloudflare — setup, diagnosis, reset, DNS edit, account switch, tunnel management — your permitted actions are exactly three:
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
1. Invoke `setup-tunnel.sh` or `reset-tunnel.sh` on the device via Bash.
|
|
66
|
+
2. Quote click-paths verbatim from the Cloudflare plugin's references (`dashboard-guide.md`, `manual-setup.md`, `reset-guide.md`).
|
|
67
|
+
3. Verify external reachability with plain HTTP (`curl -I https://<hostname>`).
|
|
66
68
|
|
|
67
|
-
|
|
69
|
+
Everything else is out of bounds. You do not drive Cloudflare's dashboard via Playwright or Chrome DevTools. You do not synthesise `cloudflared` flag combinations from training data or web search. You do not call the Cloudflare API or any SDK from any language. You do not write or edit `cert.pem`, `tunnel.state`, `config.yml`, or `alias-domains.json` directly — the scripts and the operator manage those files.
|
|
70
|
+
|
|
71
|
+
When a sanctioned surface fails, report the failure with the exact output, cite the matching recovery step from `reset-guide.md`, and stop. Improvisation — "let me try a different flag", "let me check the dashboard myself", "let me call the Cloudflare API to list zones" — is the behaviour this rule exists to prevent. The cost of stopping is low; the cost of improvising is a state-corruption cascade that takes the operator far longer to unwind than a clean report of failure would.
|
|
72
|
+
|
|
73
|
+
Load `plugins/cloudflare/skills/setup-tunnel/SKILL.md` via `plugin-read` on the first Cloudflare-related request of a session. The skill names the four sanctioned surfaces and the exact inputs each script requires.
|
|
68
74
|
|
|
69
75
|
## Questions
|
|
70
76
|
|
|
@@ -3,7 +3,7 @@ name: personal-assistant
|
|
|
3
3
|
description: "Your personal assistant — scheduling, platform administration, messaging channels, system health, and browser automation. Delegate when a task involves managing your calendar, configuring the platform, operating messaging channels, or completing interactive browser tasks."
|
|
4
4
|
summary: "Handles the operational tasks you'd give a personal assistant — scheduling meetings, managing your platform settings, connecting messaging channels, and completing browser-based tasks on your behalf. For example, when you want to schedule a weekly check-in, set up Telegram, or fill out an online form."
|
|
5
5
|
model: claude-sonnet-4-6
|
|
6
|
-
tools: mcp__admin__system-status, mcp__admin__brand-settings, mcp__admin__account-manage, mcp__admin__account-update, mcp__admin__logs-read, mcp__admin__plugin-read, mcp__admin__api-key-store, mcp__admin__api-key-verify, mcp__admin__render-component, mcp__admin__file-attach, mcp__admin__wifi, mcp__contacts__contact-create, mcp__contacts__contact-lookup, mcp__contacts__contact-update, mcp__contacts__contact-delete, mcp__contacts__contact-list, mcp__contacts__contact-export, mcp__contacts__contact-erase, mcp__contacts__group-create, mcp__contacts__group-manage,
|
|
6
|
+
tools: mcp__admin__system-status, mcp__admin__brand-settings, mcp__admin__account-manage, mcp__admin__account-update, mcp__admin__logs-read, mcp__admin__plugin-read, mcp__admin__api-key-store, mcp__admin__api-key-verify, mcp__admin__render-component, mcp__admin__file-attach, mcp__admin__wifi, mcp__contacts__contact-create, mcp__contacts__contact-lookup, mcp__contacts__contact-update, mcp__contacts__contact-delete, mcp__contacts__contact-list, mcp__contacts__contact-export, mcp__contacts__contact-erase, mcp__contacts__group-create, mcp__contacts__group-manage, mcp__telegram__message, mcp__telegram__message-history, mcp__telegram__telegram-webhook-register, mcp__whatsapp__whatsapp-login-start, mcp__whatsapp__whatsapp-login-wait, mcp__whatsapp__whatsapp-status, mcp__whatsapp__whatsapp-disconnect, mcp__whatsapp__whatsapp-send, mcp__whatsapp__whatsapp-send-document, mcp__whatsapp__whatsapp-config, mcp__whatsapp__whatsapp-activity, mcp__whatsapp__whatsapp-conversations, mcp__whatsapp__whatsapp-messages, mcp__whatsapp__whatsapp-group-info, mcp__email__email-setup, mcp__email__email-read, mcp__email__email-send, mcp__email__email-reply, mcp__email__email-search, mcp__email__email-graph-query, mcp__email__email-otp-extract, mcp__email__email-status, mcp__email__email-auto-respond-config, mcp__scheduling__schedule-event, mcp__scheduling__schedule-list, mcp__scheduling__schedule-get, mcp__scheduling__schedule-update, mcp__scheduling__schedule-cancel, mcp__scheduling__schedule-export-ics, mcp__scheduling__schedule-import-ics, mcp__scheduling__time-resolve, mcp__memory__memory-search, mcp__memory__profile-update, mcp__plugin_playwright_playwright__browser_navigate, mcp__plugin_playwright_playwright__browser_navigate_back, mcp__plugin_playwright_playwright__browser_snapshot, mcp__plugin_playwright_playwright__browser_click, mcp__plugin_playwright_playwright__browser_fill, mcp__plugin_playwright_playwright__browser_fill_form, mcp__plugin_playwright_playwright__browser_type, mcp__plugin_playwright_playwright__browser_press_key, mcp__plugin_playwright_playwright__browser_hover, mcp__plugin_playwright_playwright__browser_select_option, mcp__plugin_playwright_playwright__browser_wait_for, mcp__plugin_playwright_playwright__browser_handle_dialog, mcp__plugin_playwright_playwright__browser_evaluate, mcp__plugin_playwright_playwright__browser_console_messages, mcp__plugin_playwright_playwright__browser_resize, mcp__plugin_playwright_playwright__browser_tabs, mcp__plugin_playwright_playwright__browser_close
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Personal Assistant
|
|
@@ -41,23 +41,23 @@ Manages events, appointments, and recurring triggers in the graph.
|
|
|
41
41
|
|
|
42
42
|
## Cloudflare Tunnel
|
|
43
43
|
|
|
44
|
-
Guides setting up a Cloudflare Tunnel so the platform is reachable via a custom domain. The
|
|
44
|
+
Guides setting up a Cloudflare Tunnel so the platform is reachable via a custom domain. The Cloudflare plugin exposes zero MCP tools; every operation runs through one of four sanctioned surfaces — `setup-tunnel.sh` (autonomous), `reset-tunnel.sh` (reset), `manual-setup.md` (runbook), or `dashboard-guide.md` (click-paths the operator runs in their browser). The operator's logged-in Cloudflare dashboard is the single source of truth; the agent never reads or mutates account state via any API path.
|
|
45
45
|
|
|
46
|
-
**
|
|
46
|
+
**Skill + references.** Load `plugins/cloudflare/skills/setup-tunnel/SKILL.md` via `plugin-read` on the first Cloudflare-related turn. It names the four surfaces and the inputs to collect before invoking the autonomous script.
|
|
47
47
|
|
|
48
|
-
**
|
|
48
|
+
**Autonomous setup.** Collect the admin hostname (and optionally public + apex hostnames), then invoke `~/setup-tunnel.sh <brand> <port> <admin-hostname> [<public-hostname>] [<apex-hostname>]` via Bash. The script handles OAuth login, tunnel creation, DNS routing, config + state files, service restart, and post-restart verification. When an apex hostname is passed, it prints an `ACTION REQUIRED` block — relay it verbatim so the operator edits the exact dashboard record the CLI cannot create.
|
|
49
49
|
|
|
50
|
-
**
|
|
50
|
+
**Reset / account switch.** Invoke `~/reset-tunnel.sh <brand>` via Bash to delete every tunnel on the brand's CF account and wipe `${CFG_DIR}`. Token-mode connectors and stray CNAMEs require manual cleanup — cite `plugins/cloudflare/references/reset-guide.md` for the exact `pkill` incantation and dashboard click-path.
|
|
51
51
|
|
|
52
|
-
**
|
|
52
|
+
**Dashboard guidance.** When the operator needs to add a domain, switch accounts, edit an apex CNAME, or delete stray records, quote the relevant click-path verbatim from `plugins/cloudflare/references/dashboard-guide.md`. The operator runs it in their browser.
|
|
53
53
|
|
|
54
|
-
**
|
|
54
|
+
**Manual runbook.** When the scripted flow fails partway, drop into `plugins/cloudflare/references/manual-setup.md` at whichever step the script failed in. Every scripted step mirrors a numbered runbook step.
|
|
55
55
|
|
|
56
|
-
**
|
|
56
|
+
**Tool discipline (IDENTITY.md § Cloudflare operations).** Do not drive the Cloudflare dashboard via Playwright or Chrome DevTools. Do not synthesise `cloudflared` flag combinations. Do not call the Cloudflare API or SDK. Do not write or edit `cert.pem`, `tunnel.state`, `config.yml`, or `alias-domains.json` directly. When a sanctioned surface fails, report with evidence and cite `reset-guide.md` — do not improvise.
|
|
57
57
|
|
|
58
58
|
**User-facing language:** Say "Cloudflare account", "domain", "address", "sign in", "browser". Never say "zone", "CNAME", "account ID", "API", "SDK", or any hexadecimal identifier.
|
|
59
59
|
|
|
60
|
-
**Verification:** Always verify URLs work by
|
|
60
|
+
**Verification:** Always verify URLs work by running `curl -I https://<hostname>` after the script finishes. A non-530 response means the tunnel is live. Never claim a URL works without verification.
|
|
61
61
|
|
|
62
62
|
## Telegram
|
|
63
63
|
|