@craftsamo/cloudflare-tools 0.0.0-stage → 0.1.0

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.
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "craft-agent",
3
+ "interface": {
4
+ "displayName": "Craft Agent"
5
+ },
6
+ "plugins": [
7
+ {
8
+ "name": "cloudflare-tools",
9
+ "source": {
10
+ "source": "local",
11
+ "path": "./"
12
+ },
13
+ "policy": {
14
+ "installation": "AVAILABLE",
15
+ "authentication": "ON_INSTALL"
16
+ },
17
+ "category": "Developer Tools"
18
+ }
19
+ ]
20
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "cloudflare-tools",
3
+ "version": "0.1.0",
4
+ "description": "Cloudflare tools for coding agents: zones, DNS, analytics, Workers, Pages, storage and tunnels.",
5
+ "author": {
6
+ "name": "craftsamo",
7
+ "url": "https://github.com/craft-agent"
8
+ },
9
+ "homepage": "https://github.com/craft-agent/cloudflare-tools#readme",
10
+ "repository": "https://github.com/craft-agent/cloudflare-tools",
11
+ "license": "MIT"
12
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "$schema": "https://anthropic.com/claude-code/marketplace.schema.json",
3
+ "name": "craft-agent",
4
+ "description": "Plugins by Craft Agent.",
5
+ "owner": {
6
+ "name": "Craft Agent",
7
+ "url": "https://github.com/craft-agent"
8
+ },
9
+ "plugins": [
10
+ {
11
+ "name": "cloudflare-tools",
12
+ "source": "./",
13
+ "description": "Cloudflare tools for coding agents: zones, DNS, analytics, Workers, Pages, storage and tunnels.",
14
+ "category": "development"
15
+ }
16
+ ]
17
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "cloudflare-tools",
3
+ "version": "0.1.0",
4
+ "description": "Cloudflare tools for coding agents: zones, DNS, analytics, Workers, Pages, storage and tunnels.",
5
+ "author": {
6
+ "name": "craftsamo",
7
+ "url": "https://github.com/craft-agent"
8
+ },
9
+ "homepage": "https://github.com/craft-agent/cloudflare-tools#readme",
10
+ "repository": "https://github.com/craft-agent/cloudflare-tools",
11
+ "license": "MIT",
12
+ "mcpServers": {
13
+ "cloudflare-tools": {
14
+ "command": "node",
15
+ "args": ["${CLAUDE_PLUGIN_ROOT}/dist/mcp.js"]
16
+ }
17
+ }
18
+ }
package/.mcp.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "mcpServers": {
3
+ "cloudflare-tools": {
4
+ "command": "node",
5
+ "args": ["${CLAUDE_PLUGIN_ROOT}/dist/mcp.js"]
6
+ }
7
+ }
8
+ }
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 craftsamo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,299 @@
1
- # Temporary Holding Version
1
+ # cloudflare-tools
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Cloudflare tools for coding agents: zones, DNS, analytics, Workers, Pages, storage and tunnels.
4
+
5
+ | Harness | Delivery | Pinned by |
6
+ | -------------- | ---------------------------------------------- | ------------------------------ |
7
+ | OpenCode V2 | native plugin (npm package, with skills) | the version in the package |
8
+ | OpenCode V1 | native plugin (npm package, no skills) | the version in the package |
9
+ | Claude Code | plugin: MCP server and skills | the release tag, as the ref |
10
+ | Codex | plugin: MCP server and skills | the release tag, as the ref |
11
+ | Grok Build | plugin: MCP server and skills | the release tag, as `@ref` |
12
+ | Antigravity | plugin: MCP server and skills | the release tag's tree URL |
13
+ | Hermes Agent | native plugin (Python, calls the command line) | the release commit, as the SHA |
14
+ | other MCP host | MCP server from npm | the version in the package |
15
+
16
+ The tools need [Node.js](https://nodejs.org/) 24 or later.
17
+ [`docs/conventions.md`](docs/conventions.md) describes how the tools are named
18
+ and how they behave.
19
+
20
+ ## Install
21
+
22
+ Install from a release, never from the default branch: a release is a tag whose
23
+ commit carries the built `dist/`, and the default branch does not. In the
24
+ commands below, `<version>` is a release's version (`1.2.3`) and `<sha>` is the
25
+ commit its tag names:
26
+
27
+ ```sh
28
+ gh api repos/craft-agent/cloudflare-tools/commits/v<version> --jq .sha
29
+ ```
30
+
31
+ ### OpenCode
32
+
33
+ OpenCode V2 takes the package and its options in `opencode.json`:
34
+
35
+ ```json
36
+ {
37
+ "plugins": [{ "package": "@craftsamo/cloudflare-tools@<version>", "options": { "read_only": false } }],
38
+ "permissions": [{ "action": "cloudflare_*", "resource": "*", "effect": "ask" }]
39
+ }
40
+ ```
41
+
42
+ OpenCode V1 takes the package as a string, or as a pair with its options:
43
+
44
+ ```json
45
+ {
46
+ "plugin": [["@craftsamo/cloudflare-tools@<version>", { "read_only": false }]],
47
+ "permission": { "cloudflare_*": "ask" }
48
+ }
49
+ ```
50
+
51
+ OpenCode allows any action no rule names, so the plugin's request is granted
52
+ silently unless a rule says `ask`. Read tools never ask, so the `cloudflare_*` glob
53
+ is safe.
54
+
55
+ V1 registers no skills. Unpack the package and copy its `skills/*` folders into
56
+ `~/.config/opencode/skills/`:
57
+
58
+ ```sh
59
+ npm pack @craftsamo/cloudflare-tools@<version>
60
+ tar -xzf craftsamo-cloudflare-tools-<version>.tgz
61
+ mkdir -p ~/.config/opencode/skills
62
+ cp -r package/skills/* ~/.config/opencode/skills/
63
+ rm -rf package craftsamo-cloudflare-tools-<version>.tgz
64
+ ```
65
+
66
+ ### Claude Code
67
+
68
+ ```sh
69
+ claude plugin marketplace add craft-agent/cloudflare-tools#v<version>
70
+ claude plugin install cloudflare-tools@craft-agent
71
+ ```
72
+
73
+ ### Codex
74
+
75
+ ```sh
76
+ codex plugin marketplace add craft-agent/cloudflare-tools --ref v<version>
77
+ codex plugin add cloudflare-tools@craft-agent
78
+ ```
79
+
80
+ Codex turns `-` into `_` in server names, so it shows the tools as
81
+ `mcp__cloudflare_tools__cloudflare_*`. It starts the MCP server in the plugin's
82
+ install directory, which is never the caller's working tree.
83
+
84
+ ### Grok Build
85
+
86
+ ```sh
87
+ grok plugin install craft-agent/cloudflare-tools@v<version> --trust
88
+ ```
89
+
90
+ Grok starts the MCP server in the session's working directory.
91
+
92
+ ### Antigravity
93
+
94
+ Install from the tree of the release tag, never from the default branch, which
95
+ has no built `dist/`; Antigravity clones the tag into
96
+ `~/.gemini/config/plugins/cloudflare-tools`.
97
+
98
+ ```sh
99
+ agy plugin install https://github.com/craft-agent/cloudflare-tools/tree/v<version>
100
+ ```
101
+
102
+ ### Hermes Agent
103
+
104
+ Hermes installs a commit, not a tag, and the plugin installs disabled:
105
+
106
+ ```sh
107
+ hermes plugins install craft-agent/cloudflare-tools --ref <sha>
108
+ hermes plugins enable cloudflare-tools
109
+ ```
110
+
111
+ If a Hermes gateway is already running, restart it (`hermes gateway restart`) to
112
+ load the plugin.
113
+
114
+ ### Any other MCP host
115
+
116
+ Add the server to the host's MCP configuration. Flags go in `args`:
117
+
118
+ ```json
119
+ {
120
+ "mcpServers": {
121
+ "cloudflare-tools": {
122
+ "command": "npx",
123
+ "args": ["-y", "@craftsamo/cloudflare-tools@<version>", "--read-only"]
124
+ }
125
+ }
126
+ }
127
+ ```
128
+
129
+ ## Tools and skills
130
+
131
+ Each toolset comes with a skill that tells an agent how to use its tools.
132
+
133
+ ### Account (`account`)
134
+
135
+ Account credentials, token verification, and audit logs.
136
+
137
+ | Tool | What it does | Class |
138
+ | ------------------------- | ------------------------------------------------------------------------------------------ | ----- |
139
+ | `cloudflare_account_read` | `view` account details and token status, `list` configured accounts, or query `audit` logs | read |
140
+
141
+ The skill is [`cloudflare-account`](skills/cloudflare-account/SKILL.md), shown as
142
+ `cloudflare-tools:cloudflare-account` in Claude Code and
143
+ `cloudflare-tools:account` in Hermes.
144
+
145
+ ### Zones (`zones`)
146
+
147
+ Zone lookup, settings (read and change), Universal SSL, certificates, and DNSSEC.
148
+
149
+ | Tool | What it does | Class |
150
+ | --------------------------------- | ---------------------------------------------------------------------------------- | -------------- |
151
+ | `cloudflare_zone_read` | `list` zones, `view` details, read `settings`, Universal `ssl` status, or `dnssec` | read |
152
+ | `cloudflare_zone_setting_edit` | change 1–20 zone settings in order; refuses a change that lowers protection | overwrite |
153
+ | `cloudflare_zone_setting_weaken` | change zone settings in ways that lower a visitor's protection; always asks first | administrative |
154
+ | `cloudflare_zone_cache_purge` | purge cached copies of up to 100 URLs, hosts, prefixes or tags in a zone | idempotent |
155
+ | `cloudflare_zone_cache_purge_all` | purge the whole cache of a zone; always asks first | administrative |
156
+ | `cloudflare_zone_dnssec_enable` | turn DNSSEC on for a zone; harmless until registrar publishes the DS record | idempotent |
157
+ | `cloudflare_zone_dnssec_disable` | turn DNSSEC off for a zone; requires DS removed at registrar first | administrative |
158
+
159
+ The skill is [`cloudflare-zones`](skills/cloudflare-zones/SKILL.md), shown as
160
+ `cloudflare-tools:cloudflare-zones` in Claude Code and
161
+ `cloudflare-tools:zones` in Hermes.
162
+
163
+ ## Adding a tool
164
+
165
+ 1. Write the spec in `src/core/<domain>/<verb>.ts` with `defineTool`: an ID
166
+ `<prefix>_<domain>_<verb>`, a title and description, the Zod argument and
167
+ output schemas, its toolset and write class, and `execute(args, context)`.
168
+ A write tool also gives `targets(args, context)`: what the call writes to,
169
+ as a permission rule should name it.
170
+ 2. Test it beside the spec (`<verb>.test.ts`), calling it through `invoke` as
171
+ the entry points do. A tool that runs a program is tested against a fake of
172
+ that program on `PATH`; no test reaches a real service.
173
+ 3. List it in `src/tools.ts`. A new toolset goes into `toolsets` in
174
+ `src/project.ts` (and `defaultToolsets` when it is on by default).
175
+ 4. Add or update the toolset's skill, `skills/<prefix>-<toolset>/SKILL.md`.
176
+ 5. Run `pnpm run build && pnpm run manifests` to list the tool in
177
+ `plugin.yaml`, then describe it under "Tools and skills".
178
+
179
+ [`docs/conventions.md`](docs/conventions.md) has the rules each step follows.
180
+
181
+ ## Reads and writes
182
+
183
+ Every read tool is named `<prefix>_<domain>_read`. Reads can run unasked;
184
+ writes are confirmed by the harness.
185
+
186
+ | Harness | Reads without asking |
187
+ | ----------- | -------------------------------------------------------------------------------------------------------------------- |
188
+ | OpenCode | always; the plugin asks only before a write |
189
+ | Claude Code | the rule `mcp__plugin_cloudflare-tools_cloudflare-tools__*_read` in `permissions.allow` of `~/.claude/settings.json` |
190
+ | Codex | always; Codex runs tools that declare `readOnlyHint` unasked, as the read tools do |
191
+ | Grok Build | `grok --allow 'MCPTool(cloudflare-tools__*_read)' --allow 'MCPTool(cloudflare_*_read)'` (both rules; see below) |
192
+ | Antigravity | the rule `mcp(cloudflare-tools_cloudflare-tools/<tool id>)` in `permissions.allow`, one for each read tool |
193
+ | Hermes | always; the plugin asks only before a write |
194
+
195
+ Where a write is asked about, and where it is not:
196
+
197
+ - **OpenCode** grants any action no rule names, so a write runs unasked unless
198
+ a rule asks for it: add the `cloudflare_*` rule shown under [OpenCode](#opencode).
199
+ - **Codex** under `codex exec`, and **Grok Build** under `grok -p`, refuse a
200
+ write they cannot ask about, unless it is allowed beforehand.
201
+ - **Grok Build** calls the plugin's tools through its `use_tool` tool, and the
202
+ agent often names a tool without its server first. Grok checks the rules
203
+ against the name as given, so the server-qualified rule alone does not match
204
+ that first call. The second rule matches the short name; a write still
205
+ matches neither.
206
+ - **Antigravity** asks before any MCP tool no rule allows, reads included, and
207
+ names the plugin's server `cloudflare-tools_cloudflare-tools` (plugin,
208
+ then server). `agy -p` refuses a tool it cannot ask about.
209
+ - **Hermes** `hermes chat -q` refuses a write it cannot ask about; `hermes -z`
210
+ and `--yolo` skip approval, so writes then run unasked.
211
+
212
+ ## Settings
213
+
214
+ Every entry point takes the same settings. A flag wins over its environment
215
+ variable, and an option or setting wins over the variable too.
216
+
217
+ | Setting | Flag | Variable | Meaning |
218
+ | --------------- | ----------------- | -------------------------------- | ----------------------------------------------------------------------------- |
219
+ | `toolsets` | `--toolsets` | `CLOUDFLARE_TOOLS_TOOLSETS` | the toolsets that are on, or `all`; default those `src/project.ts` names |
220
+ | `read_only` | `--read-only` | `CLOUDFLARE_TOOLS_READ_ONLY` | registers no tool that writes; wins over every other setting |
221
+ | `tools` | `--tools` | `CLOUDFLARE_TOOLS_TOOLS` | single tools to add by ID, whatever their toolset |
222
+ | `exclude_tools` | `--exclude-tools` | `CLOUDFLARE_TOOLS_EXCLUDE_TOOLS` | single tools to remove by ID; wins over `tools` and `toolsets` |
223
+ | `confirm` | `--confirm` | `CLOUDFLARE_TOOLS_CONFIRM` | MCP server only: `harness` (default) or `elicitation`, as the conventions say |
224
+
225
+ Lists are comma-separated in a flag or a variable. Where each harness reads them:
226
+
227
+ - **OpenCode** takes the plugin `options` shown above, with lists as arrays and
228
+ `read_only` as a boolean.
229
+ - **Hermes** takes `plugins.entries.cloudflare-tools.settings` in
230
+ `config.yaml`:
231
+
232
+ ```yaml
233
+ plugins:
234
+ entries:
235
+ cloudflare-tools:
236
+ settings:
237
+ read_only: false
238
+ exclude_tools: []
239
+ ```
240
+
241
+ - **Claude Code and Antigravity** start the plugin's server without flags and
242
+ pass it the client's environment, so set the variables in the environment the
243
+ harness runs in.
244
+ - **Codex and Grok Build** pass no environment to a plugin's MCP server, so the
245
+ variables have no effect there. To change settings in Codex, add the server
246
+ under `[mcp_servers]` in Codex's config with flags in `args` (as in
247
+ [Any other MCP host](#any-other-mcp-host)) instead of using the plugin.
248
+
249
+ ### Credentials
250
+
251
+ The tools call Cloudflare with API tokens read from the environment, never
252
+ from a setting or an argument. Each token comes with the id of the one
253
+ account it acts on:
254
+
255
+ | Variables | Picked by |
256
+ | --------------------------------------------------------------- | -------------------------------------------- |
257
+ | `CLOUDFLARE_API_TOKEN`, `CLOUDFLARE_ACCOUNT_ID` | `account` left out, or `account: "default"` |
258
+ | `CLOUDFLARE_API_TOKEN_<LABEL>`, `CLOUDFLARE_ACCOUNT_ID_<LABEL>` | `account: "<label>"`, the label in lowercase |
259
+
260
+ - The unlabeled pair has the names Wrangler reads. A label is 1 to 24
261
+ lowercase letters, digits and `_`, written in capitals in its variables
262
+ (`my_site` → `CLOUDFLARE_API_TOKEN_MY_SITE`).
263
+ - With `account` left out, a call takes the unlabeled pair, or the only label
264
+ when there is no unlabeled pair; with several labels and no unlabeled pair
265
+ it fails and lists them.
266
+ - Use an API token scoped to what the tools should do; a Global API Key is
267
+ refused.
268
+ - The variables reach the tools the way the settings do: in the environment
269
+ OpenCode, Hermes, Claude Code and Antigravity run in, and in the `env` of an
270
+ MCP host's server entry. Codex and Grok Build pass no environment to a
271
+ plugin's server, so add the server to their own MCP configuration instead.
272
+
273
+ ## Layout
274
+
275
+ - `src/project.ts` — the package's name, tool ID prefix, setting prefix and
276
+ toolsets.
277
+ - `src/core/` — the tool contract and the tools, free of any harness and of
278
+ the project's names.
279
+ - `src/tools.ts` — the list of every tool, which each entry point registers.
280
+ - `src/mcp/` — the MCP server, built to `dist/mcp.js` and run by
281
+ `cloudflare-tools`.
282
+ - `src/opencode/` — the OpenCode plugin, built to `dist/opencode.js`.
283
+ - `src/cli/` — the command line the Hermes plugin calls, built to `dist/cli.js`
284
+ and run by `cloudflare-tools-cli`.
285
+ - `src/hermes/`, `plugin.yaml` and `__init__.py` — the Hermes plugin.
286
+ - `skills/` — one skill per toolset, `skills/<name>/SKILL.md`, which every
287
+ harness that takes skills loads from the package or plugin root.
288
+ - `plugin.json`, `mcp.json`, `.mcp.json`, `.claude-plugin/`, `.agents/plugins/`,
289
+ `.antigravity-plugin/` and `mcp_config.json` — the plugin manifests of the
290
+ other harnesses. The root `.mcp.json` is the configuration Grok Build reads
291
+ (with `${CLAUDE_PLUGIN_ROOT}`, the variable both Grok Build and Claude Code
292
+ expand); when working on this repository in Claude Code, decline the project
293
+ MCP server it offers from that file.
294
+
295
+ How a release is made is in [`RELEASING.md`](RELEASING.md).
296
+
297
+ ## License
298
+
299
+ [MIT](LICENSE)
package/__init__.py ADDED
@@ -0,0 +1,36 @@
1
+ """Loads the plugin package from ``src/hermes/cloudflare_tools_hermes`` for Hermes, which imports this file.
2
+
3
+ The package is loaded as ``<this module's name>._impl``, so Hermes, which evicts
4
+ everything under a plugin's module name when it reloads it or loads it for another
5
+ profile, evicts the package too, and each install path gets a package of its own.
6
+ """
7
+
8
+ import importlib.util
9
+ import sys
10
+ from pathlib import Path
11
+
12
+ _NAME = f"{__name__}._impl"
13
+ _PACKAGE_DIR = Path(__file__).resolve().parent / "src" / "hermes" / "cloudflare_tools_hermes"
14
+
15
+
16
+ def _evict() -> None:
17
+ """Drop the package and its submodules from ``sys.modules``."""
18
+ for name in list(sys.modules):
19
+ if name == _NAME or name.startswith(f"{_NAME}."):
20
+ sys.modules.pop(name, None)
21
+
22
+
23
+ _spec = importlib.util.spec_from_file_location(
24
+ _NAME, _PACKAGE_DIR / "__init__.py", submodule_search_locations=[str(_PACKAGE_DIR)]
25
+ )
26
+ _module = importlib.util.module_from_spec(_spec)
27
+ _evict()
28
+ sys.modules[_NAME] = _module
29
+ try:
30
+ _spec.loader.exec_module(_module)
31
+ except BaseException:
32
+ _evict()
33
+ raise
34
+
35
+ register = _module.register
36
+ __all__ = ["register"]