dominusnode-moltbook 2.2.0__tar.gz

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,65 @@
1
+ # Changelog
2
+
3
+ ## 2.0.0 (2026-11-06)
4
+
5
+ ### Breaking
6
+
7
+ - Rebuilt on the DominusNode SDK v2: exposes exactly the 19 standard relay-network tools
8
+ (fetch, proxy_url, network_policy/pricing/stats, balance, transactions, topup_crypto, check_payment, usage,
9
+ active_sessions, report_session, node_list, node_tier, node_setup_guide, credits_balance, credits_convert,
10
+ payouts_list, x402_info).
11
+ - Removed Stripe/PayPal top-ups, plans, slots, teams/agentic-wallet/key management, email/password and MFA
12
+ flows, hardcoded prices and dc-/residential- pool prefixes.
13
+ - Removed the bundled HTTP client and SSRF code; the SDK now provides HTTP, DNS-rebinding checks, OFAC refusal
14
+ and credential scrubbing.
15
+ - Removed MoltbookClient and every Moltbook API call: account registration, posting, commenting, submolt creation, voting, browsing, ETH wallet signing and rotating-IP posting. The package is now only the framework-neutral tool surface (tool_definitions, DominusNodeTools, make_tool_callables).
16
+
17
+ ### Added
18
+
19
+ - Live pricing via network_pricing, node earnings tools and a node agent setup guide.
20
+ - The API key is read only from DOMINUSNODE_API_KEY/config; proxy_url returns a key placeholder.
21
+
22
+ ## 1.1.0
23
+
24
+ - Expand to 53 tools: add 27 new Dominus Node management tools
25
+ - New proxy: dn_get_proxy_status (GET /api/proxy/status)
26
+ - New wallet: get_transactions, get_forecast, check_payment
27
+ - New usage: get_daily_usage, get_top_hosts
28
+ - New account: register_account, login_account, get_account_info, verify_email, resend_verification, update_password
29
+ - New API keys: list_keys, create_key, revoke_key
30
+ - New plans: get_plan, list_plans, change_plan
31
+ - New teams: team_delete, team_revoke_key, team_list_keys, team_list_members, team_add_member, team_remove_member, team_invite_member, team_list_invites, team_cancel_invite
32
+
33
+ ## 1.0.1
34
+
35
+ - Fix branding: replace "DomiNode" with "Dominus Node" throughout
36
+
37
+ ## 1.0.0 (2026-02-24)
38
+
39
+ ### Added
40
+
41
+ - Initial release with 10 Moltbook tools + 22 Dominus Node management tools (32 total)
42
+ - Moltbook tools: register, browse_posts, get_post, create_post, comment, vote, list_submolts, create_submolt, get_profile, get_proxy_status
43
+ - All Moltbook requests routed through Dominus Node rotating proxy gateway for IP rotation
44
+ - Ethereum wallet authentication (EIP-191 personal_sign format) with X-Address, X-Signature, X-Timestamp headers
45
+ - Pluggable signing function (stub HMAC signer for dev, supports custom eth_account signer for production)
46
+ - Dominus Node management: wallet balance, usage, proxy config, sessions, agentic wallets (CRUD + fund + freeze/unfreeze), teams (CRUD + fund + keys + usage + role updates), x402 info, PayPal top-up
47
+ - Full security suite: SSRF prevention (DNS rebinding, Teredo/6to4, IPv4-mapped/compatible IPv6, hex/octal/decimal normalization), OFAC blocking, credential scrubbing (API keys + ETH private keys), prototype pollution prevention
48
+ - 10 MB response cap, redirect following disabled, 30s timeout
49
+ - 120+ tests covering all security vectors, input validation, auth flows, and API interactions
50
+
51
+ ## [2.2.0] - 2026-11-13
52
+
53
+ ### Changed
54
+ - Proxy traffic now goes to the gateway's TLS (HTTPS proxy) listener on port 8443 by default, and `proxy_url` returns `https://...:8443`. Production gateways refuse credentials on plaintext 8080/1080, so `fetch` failed on first use before. `DOMINUSNODE_PROXY_URL=https://host[:port]` sets the gateway host and TLS port (same variable as the MCP server; self-hosted coordinators publish 8444), `DOMINUSNODE_PROXY_TLS_PORT` sets only the port, and `DOMINUSNODE_PROXY_INSECURE=1` selects plaintext for local development.
55
+ - The node setup guide uses the published node image (`ghcr.io/0xcircuitbreaker/dominusnode-node`), which has the official coordinator pins baked in. A plain source build has none and now refuses to start.
56
+ - Requires the DominusNode SDK 2.2.0 or later (relay error codes on refused CONNECTs).
57
+
58
+ ## [2.1.0] - 2026-11-12
59
+
60
+ ### Added
61
+ - The fetch tool's `ip_class` accepts `masked` (cheapest, VPN/anonymizer exits, opt-in; never used unless asked).
62
+
63
+ ### Changed
64
+ - Requires the DominusNode SDK 2.1.0 or later (`masked` support).
65
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Dominus Node
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.
@@ -0,0 +1,8 @@
1
+ # sdist contents: package source, metadata and docs only (see scripts/release/check-artifacts.mjs)
2
+ include README.md
3
+ include CHANGELOG.md
4
+ include LICENSE
5
+ prune tests
6
+ exclude conftest.py
7
+ prune examples
8
+ global-exclude *.py[cod] __pycache__ *.map .env .env.* *.log
@@ -0,0 +1,104 @@
1
+ Metadata-Version: 2.4
2
+ Name: dominusnode-moltbook
3
+ Version: 2.2.0
4
+ Summary: DominusNode v2 standard tool set (19 relay-network tools) for agent runtimes, built on the dominusnode SDK
5
+ License-Expression: MIT
6
+ Project-URL: Homepage, https://github.com/0xcircuitbreaker/DomiNode/tree/master/integrations/moltbook
7
+ Project-URL: Repository, https://github.com/0xcircuitbreaker/DomiNode
8
+ Project-URL: Issues, https://github.com/0xcircuitbreaker/DomiNode/issues
9
+ Project-URL: Changelog, https://github.com/0xcircuitbreaker/DomiNode/blob/master/integrations/moltbook/CHANGELOG.md
10
+ Requires-Python: >=3.9
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: dominusnode<3,>=2.2.0
14
+ Provides-Extra: dev
15
+ Requires-Dist: pytest>=7.0; extra == "dev"
16
+ Dynamic: license-file
17
+
18
+ # dominusnode-moltbook
19
+
20
+ Gives agents the DominusNode AI-agent relay network: fetch public web pages through exit IPs contributed by
21
+ other agents' nodes, pay per GB from a prepaid crypto wallet, and earn by contributing your own IP with the
22
+ node agent. Built on the official DominusNode SDK v2; HTTP, SSRF/DNS-rebinding protection, OFAC refusal and
23
+ credential scrubbing all come from the SDK.
24
+
25
+ ## Install
26
+
27
+ ```bash
28
+ pip install dominusnode-moltbook
29
+ ```
30
+
31
+ ## Configuration
32
+
33
+ | Variable | Required | Purpose |
34
+ |---|---|---|
35
+ | `DOMINUSNODE_API_KEY` | yes | Your `dn_live_` API key. Read from the environment/config only; never a tool argument, never in tool output. |
36
+ | `DOMINUSNODE_BASE_URL` | no | API base URL (default `https://api.dominusnode.com`). |
37
+ | `DOMINUSNODE_PROXY_HOST` | no | Gateway host (default `proxy.dominusnode.com`). |
38
+ | `DOMINUSNODE_PROXY_URL` | no | `https://host[:port]` of the gateway's TLS proxy (default port 8443; self-hosted coordinators use 8443 too). |
39
+ | `DOMINUSNODE_PROXY_INSECURE` | no | `1` = plaintext gateway on 8080 (local development only; production refuses it). |
40
+
41
+ ## Usage
42
+
43
+ > **2.0.0 scope change.** Versions 1.x shipped a `MoltbookClient` that registered Moltbook accounts and created
44
+ > posts, comments, submolts and votes, routing each request through a different rotating IP. That code is
45
+ > removed and will not return: this package no longer talks to the Moltbook API, registers accounts, signs
46
+ > with wallet keys or posts anything. Agents can still read public pages with `dominusnode_fetch`.
47
+
48
+ The package is a framework-neutral tool surface: JSON-schema definitions plus a dispatcher.
49
+
50
+ ```python
51
+ from dominusnode_moltbook import DominusNodeTools, tool_definitions
52
+
53
+ tools = DominusNodeTools() # key from DOMINUSNODE_API_KEY
54
+ for d in tool_definitions(): # hand these to your agent runtime's tool registry
55
+ print(d["name"], d["parameters"])
56
+ print(tools.call("dominusnode_network_pricing", {}))
57
+ ```
58
+
59
+ `make_tool_callables(tools)` returns `{name: fn(**kwargs) -> str}` for runtimes that take plain functions.
60
+ Every result is a JSON string; errors are `{"error": "..."}` with credentials scrubbed.
61
+
62
+ ## Tools (v2 standard set, 19)
63
+
64
+ | # | Tool | What it does |
65
+ |---|---|---|
66
+ | 1 | `dominusnode_fetch` | Fetch a public URL through the DominusNode relay network (GET or HEAD only, ports 80/443, no redirects followed, 10 MB cap, private/internal targets refused). |
67
+ | 2 | `dominusnode_proxy_url` | Build a relay gateway proxy URL for use in other HTTP clients. |
68
+ | 3 | `dominusnode_network_policy` | Relay network policy: allowed ports, plaintext (allowhttp) rules, blocked ranges, sanctioned countries and node attestation terms. |
69
+ | 4 | `dominusnode_network_pricing` | Live per-GB prices by exit IP class (residential, dc, mobile) and node tier revenue shares. |
70
+ | 5 | `dominusnode_network_stats` | Relay network statistics: online nodes, exit countries and IP classes. |
71
+ | 6 | `dominusnode_balance` | Prepaid requester wallet balance (cents) used to pay for relayed traffic. |
72
+ | 7 | `dominusnode_transactions` | Requester wallet transaction history (top-ups, usage debits, credit conversions). |
73
+ | 8 | `dominusnode_topup_crypto` | Create a crypto invoice to top up the requester wallet ($10-$1,000). |
74
+ | 9 | `dominusnode_check_payment` | Status of a crypto top-up invoice created by topup_crypto. |
75
+ | 10 | `dominusnode_usage` | Relayed traffic usage summary (bytes and cost) for an optional ISO 8601 date range. |
76
+ | 11 | `dominusnode_active_sessions` | Your currently active relay sessions (id, start time, status). |
77
+ | 12 | `dominusnode_report_session` | Report a burned or bad exit for one of your relay sessions so the network can rotate it. |
78
+ | 13 | `dominusnode_node_list` | Relay nodes you contribute (status, observed IP class, last seen). |
79
+ | 14 | `dominusnode_node_tier` | Your node-operator tier, revenue share and progress toward the next tier (tenure, uptime, active IPs, reputation). |
80
+ | 15 | `dominusnode_node_setup_guide` | Step-by-step instructions to earn by contributing an IP: run the DominusNode node agent, register a node, and how tiers and the self-dealing rule work. |
81
+ | 16 | `dominusnode_credits_balance` | Node-operator earnings: pending and available credit (µUSD). |
82
+ | 17 | `dominusnode_credits_convert` | Explains how to convert node credits into wallet balance. Conversion needs a wallet signature, so it runs through the DominusNode MCP server or SDK with a signer key file, not through this tool. |
83
+ | 18 | `dominusnode_payouts_list` | Your USDC payouts of node earnings with status and transaction hash. |
84
+ | 19 | `dominusnode_x402_info` | x402 micropayment info: facilitators, networks and server-reported prices. |
85
+
86
+ Notes for agents:
87
+
88
+ - Prices are never hardcoded: call `network_pricing` for the live per-GB price by IP class (residential, dc, mobile).
89
+ - `fetch` is GET/HEAD only on ports 80/443, follows no redirects and caps bodies at 10 MB. Plaintext `http://`
90
+ needs `allow_http` and is visible to the exit node.
91
+ - Routing: `country` (ISO code; sanctioned countries refused), `ip_class`, `session_id` (sticky exit).
92
+ - Signing flows (node register, withdraw, payout wallet) are deliberately not tools here; use the node agent CLI,
93
+ the DominusNode MCP server, or the SDK with a signer key file.
94
+
95
+ ## Testing
96
+
97
+ ```bash
98
+ pip install -e ../../sdks/python -e '.[dev]' # or npm install for the JS part
99
+ python -m pytest -q
100
+ ```
101
+
102
+ ## License
103
+
104
+ MIT
@@ -0,0 +1,87 @@
1
+ # dominusnode-moltbook
2
+
3
+ Gives agents the DominusNode AI-agent relay network: fetch public web pages through exit IPs contributed by
4
+ other agents' nodes, pay per GB from a prepaid crypto wallet, and earn by contributing your own IP with the
5
+ node agent. Built on the official DominusNode SDK v2; HTTP, SSRF/DNS-rebinding protection, OFAC refusal and
6
+ credential scrubbing all come from the SDK.
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ pip install dominusnode-moltbook
12
+ ```
13
+
14
+ ## Configuration
15
+
16
+ | Variable | Required | Purpose |
17
+ |---|---|---|
18
+ | `DOMINUSNODE_API_KEY` | yes | Your `dn_live_` API key. Read from the environment/config only; never a tool argument, never in tool output. |
19
+ | `DOMINUSNODE_BASE_URL` | no | API base URL (default `https://api.dominusnode.com`). |
20
+ | `DOMINUSNODE_PROXY_HOST` | no | Gateway host (default `proxy.dominusnode.com`). |
21
+ | `DOMINUSNODE_PROXY_URL` | no | `https://host[:port]` of the gateway's TLS proxy (default port 8443; self-hosted coordinators use 8443 too). |
22
+ | `DOMINUSNODE_PROXY_INSECURE` | no | `1` = plaintext gateway on 8080 (local development only; production refuses it). |
23
+
24
+ ## Usage
25
+
26
+ > **2.0.0 scope change.** Versions 1.x shipped a `MoltbookClient` that registered Moltbook accounts and created
27
+ > posts, comments, submolts and votes, routing each request through a different rotating IP. That code is
28
+ > removed and will not return: this package no longer talks to the Moltbook API, registers accounts, signs
29
+ > with wallet keys or posts anything. Agents can still read public pages with `dominusnode_fetch`.
30
+
31
+ The package is a framework-neutral tool surface: JSON-schema definitions plus a dispatcher.
32
+
33
+ ```python
34
+ from dominusnode_moltbook import DominusNodeTools, tool_definitions
35
+
36
+ tools = DominusNodeTools() # key from DOMINUSNODE_API_KEY
37
+ for d in tool_definitions(): # hand these to your agent runtime's tool registry
38
+ print(d["name"], d["parameters"])
39
+ print(tools.call("dominusnode_network_pricing", {}))
40
+ ```
41
+
42
+ `make_tool_callables(tools)` returns `{name: fn(**kwargs) -> str}` for runtimes that take plain functions.
43
+ Every result is a JSON string; errors are `{"error": "..."}` with credentials scrubbed.
44
+
45
+ ## Tools (v2 standard set, 19)
46
+
47
+ | # | Tool | What it does |
48
+ |---|---|---|
49
+ | 1 | `dominusnode_fetch` | Fetch a public URL through the DominusNode relay network (GET or HEAD only, ports 80/443, no redirects followed, 10 MB cap, private/internal targets refused). |
50
+ | 2 | `dominusnode_proxy_url` | Build a relay gateway proxy URL for use in other HTTP clients. |
51
+ | 3 | `dominusnode_network_policy` | Relay network policy: allowed ports, plaintext (allowhttp) rules, blocked ranges, sanctioned countries and node attestation terms. |
52
+ | 4 | `dominusnode_network_pricing` | Live per-GB prices by exit IP class (residential, dc, mobile) and node tier revenue shares. |
53
+ | 5 | `dominusnode_network_stats` | Relay network statistics: online nodes, exit countries and IP classes. |
54
+ | 6 | `dominusnode_balance` | Prepaid requester wallet balance (cents) used to pay for relayed traffic. |
55
+ | 7 | `dominusnode_transactions` | Requester wallet transaction history (top-ups, usage debits, credit conversions). |
56
+ | 8 | `dominusnode_topup_crypto` | Create a crypto invoice to top up the requester wallet ($10-$1,000). |
57
+ | 9 | `dominusnode_check_payment` | Status of a crypto top-up invoice created by topup_crypto. |
58
+ | 10 | `dominusnode_usage` | Relayed traffic usage summary (bytes and cost) for an optional ISO 8601 date range. |
59
+ | 11 | `dominusnode_active_sessions` | Your currently active relay sessions (id, start time, status). |
60
+ | 12 | `dominusnode_report_session` | Report a burned or bad exit for one of your relay sessions so the network can rotate it. |
61
+ | 13 | `dominusnode_node_list` | Relay nodes you contribute (status, observed IP class, last seen). |
62
+ | 14 | `dominusnode_node_tier` | Your node-operator tier, revenue share and progress toward the next tier (tenure, uptime, active IPs, reputation). |
63
+ | 15 | `dominusnode_node_setup_guide` | Step-by-step instructions to earn by contributing an IP: run the DominusNode node agent, register a node, and how tiers and the self-dealing rule work. |
64
+ | 16 | `dominusnode_credits_balance` | Node-operator earnings: pending and available credit (µUSD). |
65
+ | 17 | `dominusnode_credits_convert` | Explains how to convert node credits into wallet balance. Conversion needs a wallet signature, so it runs through the DominusNode MCP server or SDK with a signer key file, not through this tool. |
66
+ | 18 | `dominusnode_payouts_list` | Your USDC payouts of node earnings with status and transaction hash. |
67
+ | 19 | `dominusnode_x402_info` | x402 micropayment info: facilitators, networks and server-reported prices. |
68
+
69
+ Notes for agents:
70
+
71
+ - Prices are never hardcoded: call `network_pricing` for the live per-GB price by IP class (residential, dc, mobile).
72
+ - `fetch` is GET/HEAD only on ports 80/443, follows no redirects and caps bodies at 10 MB. Plaintext `http://`
73
+ needs `allow_http` and is visible to the exit node.
74
+ - Routing: `country` (ISO code; sanctioned countries refused), `ip_class`, `session_id` (sticky exit).
75
+ - Signing flows (node register, withdraw, payout wallet) are deliberately not tools here; use the node agent CLI,
76
+ the DominusNode MCP server, or the SDK with a signer key file.
77
+
78
+ ## Testing
79
+
80
+ ```bash
81
+ pip install -e ../../sdks/python -e '.[dev]' # or npm install for the JS part
82
+ python -m pytest -q
83
+ ```
84
+
85
+ ## License
86
+
87
+ MIT
@@ -0,0 +1,28 @@
1
+ """DominusNode v2 tool set for agents on Moltbook (framework-neutral).
2
+
3
+ 2.0.0 removes the old ``MoltbookClient``: it registered Moltbook accounts and
4
+ posted, commented and voted through rotating IPs. None of that remains. What
5
+ is left is the 19 standard DominusNode tools as JSON-schema definitions plus a
6
+ dispatcher, for any agent runtime (including agents active on Moltbook) that
7
+ wants relay fetching, pricing, wallet and node-earning tools::
8
+
9
+ from dominusnode_moltbook import DominusNodeTools, tool_definitions
10
+
11
+ tools = DominusNodeTools() # key from DOMINUSNODE_API_KEY
12
+ defs = tool_definitions() # [{name, description, parameters}, ...]
13
+ tools.call("dominusnode_network_pricing", {})
14
+ """
15
+
16
+ from typing import Any, Dict, List
17
+
18
+ from dominusnode_moltbook._core import PREFIX, TOOL_NAMES, TOOL_SPECS, DominusNodeTools, make_tool_callables
19
+
20
+
21
+ def tool_definitions() -> List[Dict[str, Any]]:
22
+ """The 19 tools as ``{name, description, parameters}`` (JSON Schema), names prefixed ``dominusnode_``."""
23
+ return [{"name": PREFIX + s["name"], "description": s["description"], "parameters": s["parameters"]}
24
+ for s in TOOL_SPECS]
25
+
26
+
27
+ __version__ = "2.2.0"
28
+ __all__ = ["DominusNodeTools", "TOOL_NAMES", "tool_definitions", "make_tool_callables", "__version__"]
@@ -0,0 +1,351 @@
1
+ """DominusNode v2 standard tool set (19 tools), built on the ``dominusnode`` Python SDK.
2
+
3
+ Framework-neutral: each tool has a name, an LLM-facing description and a JSON
4
+ Schema for its arguments. ``DominusNodeTools.call(name, args)`` dispatches to
5
+ the SDK and always returns a JSON string with credentials scrubbed. HTTP,
6
+ SSRF/DNS-rebinding checks, OFAC refusal and signing all live in the SDK.
7
+
8
+ The API key is read only from ``DOMINUSNODE_API_KEY`` (or passed by the host
9
+ application as configuration); it is never a tool argument or tool output.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import json
15
+ import os
16
+ import threading
17
+ from typing import Any, Callable, Dict, List, Optional
18
+
19
+ from dominusnode import DominusNodeClient, DominusNodeError, scrub_credentials, json_default
20
+
21
+ PREFIX = "dominusnode_"
22
+ MAX_BODY_CHARS = 20_000
23
+ _KEY_PLACEHOLDER = "${DOMINUSNODE_API_KEY}"
24
+
25
+ _COUNTRY = {"type": "string", "description": "ISO 3166-1 alpha-2 exit country, e.g. US. Sanctioned countries are refused."}
26
+ _IP_CLASS = {"type": "string", "enum": ["residential", "dc", "mobile", "masked"],
27
+ "description": "Exit IP class. Each class has its own per-GB price (see network_pricing); masked = cheapest, VPN/anonymizer exits, opt-in."}
28
+ _SESSION = {"type": "string", "description": "Sticky session id (1-64 alphanumeric) to keep the same exit IP."}
29
+ _ALLOW_HTTP = {"type": "boolean",
30
+ "description": "Opt in to plaintext http:// targets. Plaintext is visible to the exit node; prefer https."}
31
+ _LIMIT = {"type": "integer", "minimum": 1, "description": "Maximum number of items."}
32
+ _OFFSET = {"type": "integer", "minimum": 0, "description": "Items to skip."}
33
+
34
+
35
+ #: credits_convert needs a wallet signature; signing flows are not exposed as LLM tools.
36
+ CREDITS_CONVERT_SIGNING_MESSAGE = (
37
+ "Converting credits needs a fresh signature from the wallet linked to this account, so this tool does not convert. Use the DominusNode MCP server (tool dominusnode_credits_convert, with DOMINUSNODE_WALLET_KEY_FILE pointing at a chmod-600 wallet key file) or a DominusNode SDK's credits.convert with a signer key file. Check available credit with credits_balance."
38
+ )
39
+
40
+
41
+ def _obj(props: Optional[Dict[str, Any]] = None, required: Optional[List[str]] = None) -> Dict[str, Any]:
42
+ return {"type": "object", "properties": props or {}, "required": required or [], "additionalProperties": False}
43
+
44
+
45
+ TOOL_SPECS: List[Dict[str, Any]] = [
46
+ {"name": "fetch", "description": (
47
+ "Fetch a public URL through the DominusNode relay network (GET or HEAD only, ports 80/443, no redirects "
48
+ "followed, 10 MB cap, private/internal targets refused). Billed per GB at the live price for the exit IP "
49
+ "class (see network_pricing). http:// targets need allow_http=true and are visible to the exit node."),
50
+ "parameters": _obj({"url": {"type": "string", "description": "https:// URL (or http:// with allow_http)."},
51
+ "method": {"type": "string", "enum": ["GET", "HEAD"], "description": "HTTP method."},
52
+ "country": _COUNTRY, "ip_class": _IP_CLASS, "session_id": _SESSION,
53
+ "allow_http": _ALLOW_HTTP}, ["url"])},
54
+ {"name": "proxy_url", "description": (
55
+ "Build a relay gateway proxy URL for use in other HTTP clients. Routing flags go in the username "
56
+ "(country-XX, class-..., session-..., allowhttp-1). The password is shown as a ${DOMINUSNODE_API_KEY} "
57
+ "placeholder: substitute the key from the environment, never paste it into chat."),
58
+ "parameters": _obj({"country": _COUNTRY, "ip_class": _IP_CLASS, "session_id": _SESSION, "allow_http": _ALLOW_HTTP,
59
+ "protocol": {"type": "string", "enum": ["https", "socks5", "http"],
60
+ "description": "https (default: TLS to the gateway), socks5, or http (plaintext gateway; local dev only)."}})},
61
+ {"name": "network_policy", "description": (
62
+ "Relay network policy: allowed ports, plaintext (allowhttp) rules, blocked ranges, sanctioned countries "
63
+ "and node attestation terms."), "parameters": _obj()},
64
+ {"name": "network_pricing", "description": (
65
+ "Live per-GB prices by exit IP class (residential, dc, mobile, masked) and node tier revenue shares. Always use "
66
+ "this for prices; never assume them."), "parameters": _obj()},
67
+ {"name": "network_stats", "description": "Relay network statistics: online nodes, exit countries and IP classes.",
68
+ "parameters": _obj()},
69
+ {"name": "balance", "description": "Prepaid requester wallet balance (cents) used to pay for relayed traffic.",
70
+ "parameters": _obj()},
71
+ {"name": "transactions", "description": "Requester wallet transaction history (top-ups, usage debits, credit conversions).",
72
+ "parameters": _obj({"limit": _LIMIT, "offset": _OFFSET})},
73
+ {"name": "topup_crypto", "description": (
74
+ "Create a crypto invoice to top up the requester wallet ($10-$1,000). Returns a payment address/URL; "
75
+ "the wallet is credited after on-chain confirmation (check with check_payment)."),
76
+ "parameters": _obj({"amount_cents": {"type": "integer", "minimum": 1000, "maximum": 100000,
77
+ "description": "Amount in US cents (1000 = $10)."},
78
+ "currency": {"type": "string", "enum": ["btc", "eth", "ltc", "xmr", "zec", "usdc", "sol",
79
+ "usdt", "dai", "bnb", "link"],
80
+ "description": "Cryptocurrency to pay with."}}, ["amount_cents", "currency"])},
81
+ {"name": "check_payment", "description": "Status of a crypto top-up invoice created by topup_crypto.",
82
+ "parameters": _obj({"invoice_id": {"type": "string", "description": "Invoice UUID."}}, ["invoice_id"])},
83
+ {"name": "usage", "description": "Relayed traffic usage summary (bytes and cost) for an optional ISO 8601 date range.",
84
+ "parameters": _obj({"from": {"type": "string", "description": "ISO 8601 start."},
85
+ "to": {"type": "string", "description": "ISO 8601 end."}})},
86
+ {"name": "active_sessions", "description": "Your currently active relay sessions (id, start time, status).",
87
+ "parameters": _obj()},
88
+ {"name": "report_session", "description": (
89
+ "Report a burned or bad exit for one of your relay sessions so the network can rotate it."),
90
+ "parameters": _obj({"session_id": {"type": "string", "description": "Session UUID from active_sessions."},
91
+ "reason": {"type": "string", "enum": ["blocked", "captcha", "rate_limited", "slow",
92
+ "bad_content", "other"],
93
+ "description": "Why the exit is bad."}}, ["session_id", "reason"])},
94
+ {"name": "node_list", "description": (
95
+ "Relay nodes you contribute (status, observed IP class, last seen). Contributing IPs earns credit."),
96
+ "parameters": _obj({"limit": _LIMIT, "offset": _OFFSET})},
97
+ {"name": "node_tier", "description": (
98
+ "Your node-operator tier, revenue share and progress toward the next tier (tenure, uptime, active IPs, reputation)."),
99
+ "parameters": _obj()},
100
+ {"name": "node_setup_guide", "description": (
101
+ "Step-by-step instructions to earn by contributing an IP: run the DominusNode node agent, register a node, "
102
+ "and how tiers and the self-dealing rule work."), "parameters": _obj()},
103
+ {"name": "credits_balance", "description": "Node-operator earnings: pending and available credit (µUSD).",
104
+ "parameters": _obj()},
105
+ {"name": "credits_convert", "description": (
106
+ "Explains how to convert node credits into wallet balance. Conversion needs a wallet signature, so it runs through the DominusNode MCP server or SDK with a signer key file, not through this tool."),
107
+ "parameters": _obj({"amount_musd": {"type": "string",
108
+ "description": "Amount in micro-USD as a digit string (min 10000 = $0.01)."}},
109
+ ["amount_musd"])},
110
+ {"name": "payouts_list", "description": "Your USDC payouts of node earnings with status and transaction hash.",
111
+ "parameters": _obj({"limit": _LIMIT, "offset": _OFFSET})},
112
+ {"name": "x402_info", "description": "x402 micropayment info: facilitators, networks and server-reported prices.",
113
+ "parameters": _obj()},
114
+ ]
115
+
116
+ TOOL_NAMES: List[str] = [t["name"] for t in TOOL_SPECS]
117
+ SPECS_BY_NAME: Dict[str, Dict[str, Any]] = {t["name"]: t for t in TOOL_SPECS}
118
+
119
+ NODE_SETUP_GUIDE = "\n".join([
120
+ "DominusNode relay node setup (earn by contributing an IP)",
121
+ "",
122
+ "How earning works",
123
+ " - Your node dials OUT to the gateway (no inbound ports) and relays other agents' traffic.",
124
+ " - You earn your tier's share of each paid GB relayed; live prices and shares: network_pricing.",
125
+ " - Self-dealing earns nothing: your own, your wallet's, team's or /24's traffic never routes to your node.",
126
+ " - Tiers rise with paid tenure, uptime, active IPs and reputation (node_tier).",
127
+ " - Nodes only dial ports 80/443, never private/metadata targets or SMTP/SSH/RDP (network_policy).",
128
+ "",
129
+ "Steps",
130
+ " 1. Store your owner wallet key in a private file (never pass it to a tool or chat):",
131
+ " umask 077 && printf '%s' \"$WALLET_PRIVATE_KEY_HEX\" > ~/.dominusnode/wallet.key",
132
+ " 2. On the machine whose IP you contribute (Docker), register with the published image",
133
+ " (official coordinator pins baked in; a plain source build has none and refuses to start):",
134
+ " sudo install -d -o 1001 -g 1001 -m 700 /etc/dominusnode",
135
+ " sudo install -o 1001 -g 1001 -m 600 ~/.dominusnode/wallet.key /etc/dominusnode/wallet.key",
136
+ " export DN_API_KEY # your dn_live_ key, from the environment only",
137
+ " docker run --rm -e DN_API_KEY -e DN_WALLET_KEY_FILE=/run/dominusnode/wallet.key \\",
138
+ " -v /etc/dominusnode:/run/dominusnode ghcr.io/0xcircuitbreaker/dominusnode-node register",
139
+ " sudo rm /etc/dominusnode/wallet.key # not needed after registration",
140
+ " 3. Run it and keep it running - uptime drives your tier:",
141
+ " docker run -d --name dominusnode-node --restart unless-stopped \\",
142
+ " -v /etc/dominusnode/node.json:/run/dominusnode/node.json:ro ghcr.io/0xcircuitbreaker/dominusnode-node",
143
+ " 4. Verify with node_list and node_tier; earnings appear in credits_balance.",
144
+ "",
145
+ "Signing flows (node register, withdraw, payout wallet) are not available as tools here; use the",
146
+ "node agent CLI, the DominusNode MCP server or the SDK with a signer key file.",
147
+ ])
148
+
149
+
150
+ #: Gateway TLS (HTTPS proxy) port: production 8443; self-hosted coordinators use 8443 too.
151
+ DEFAULT_TLS_PROXY_PORT = 8443
152
+
153
+
154
+ def resolve_gateway(
155
+ proxy_host: Optional[str] = None,
156
+ tls_port: Optional[int] = None,
157
+ http_port: Optional[int] = None,
158
+ insecure: Optional[bool] = None,
159
+ env: Optional[Any] = None,
160
+ ) -> Dict[str, Any]:
161
+ """Where proxy traffic goes. TLS to the gateway's HTTPS proxy is the default: production
162
+ gateways refuse credentials on plaintext 8080/1080. ``DOMINUSNODE_PROXY_URL=https://host[:port]``
163
+ sets host and TLS port (same variable as the MCP server), ``DOMINUSNODE_PROXY_TLS_PORT`` the TLS
164
+ port, and ``DOMINUSNODE_PROXY_INSECURE=1`` selects plaintext (local development only).
165
+
166
+ Returns ``{"proxy_host", "http_port", "gateway_tls"}`` where ``gateway_tls`` is ``False`` or
167
+ ``{"port": n}``, ready for ``DominusNodeClient(gateway_tls=...)``.
168
+ """
169
+ from urllib.parse import urlsplit
170
+
171
+ e = os.environ if env is None else env
172
+
173
+ def _port(v: Any) -> Optional[int]:
174
+ try:
175
+ n = int(v)
176
+ except (TypeError, ValueError):
177
+ return None
178
+ return n if 1 <= n <= 65535 else None
179
+
180
+ url_host: Optional[str] = None
181
+ url_port: Optional[int] = None
182
+ raw = (e.get("DOMINUSNODE_PROXY_URL") or "").strip()
183
+ if raw:
184
+ u = urlsplit(raw)
185
+ if u.scheme != "https" or not u.hostname:
186
+ raise ValueError("DOMINUSNODE_PROXY_URL must be https://host[:port] (TLS to the gateway)")
187
+ if u.username or u.password:
188
+ raise ValueError("DOMINUSNODE_PROXY_URL must not contain credentials")
189
+ url_host = u.hostname.lower()
190
+ try:
191
+ url_port = _port(u.port) if u.port else DEFAULT_TLS_PROXY_PORT
192
+ except ValueError:
193
+ raise ValueError("DOMINUSNODE_PROXY_URL has an invalid port") from None
194
+ if insecure is None:
195
+ insecure = (e.get("DOMINUSNODE_PROXY_INSECURE") or "").strip() == "1"
196
+ if insecure and raw:
197
+ raise ValueError("DOMINUSNODE_PROXY_URL (TLS) and DOMINUSNODE_PROXY_INSECURE=1 are mutually exclusive")
198
+ tls = _port(tls_port) or url_port or _port(e.get("DOMINUSNODE_PROXY_TLS_PORT")) or DEFAULT_TLS_PROXY_PORT
199
+ return {
200
+ "proxy_host": proxy_host or url_host or (e.get("DOMINUSNODE_PROXY_HOST") or "").strip() or None,
201
+ "http_port": _port(http_port) or _port(e.get("DOMINUSNODE_PROXY_PORT")),
202
+ "gateway_tls": False if insecure else {"port": tls},
203
+ }
204
+
205
+
206
+ def _scrub(text: str, key: Optional[str]) -> str:
207
+ out = scrub_credentials(text)
208
+ if key:
209
+ out = out.replace(key, "[REDACTED]")
210
+ return out
211
+
212
+
213
+ def _opt_int(args: Dict[str, Any], name: str) -> Optional[int]:
214
+ v = args.get(name)
215
+ if v is None:
216
+ return None
217
+ if isinstance(v, bool):
218
+ raise ValueError(f"{name} must be an integer")
219
+ return int(v)
220
+
221
+
222
+ class DominusNodeTools:
223
+ """Dispatches the 19 standard tools to a connected ``DominusNodeClient``."""
224
+
225
+ def __init__(self, api_key: Optional[str] = None, base_url: Optional[str] = None,
226
+ proxy_host: Optional[str] = None, client: Optional[Any] = None,
227
+ tls_proxy_port: Optional[int] = None, insecure_proxy: Optional[bool] = None) -> None:
228
+ self._api_key = api_key or os.environ.get("DOMINUSNODE_API_KEY") or None
229
+ self._base_url = base_url or os.environ.get("DOMINUSNODE_BASE_URL") or None
230
+ self._gateway = resolve_gateway(proxy_host, tls_proxy_port, None, insecure_proxy)
231
+ self._proxy_host = self._gateway["proxy_host"]
232
+ self._client = client
233
+ self._connected = client is not None
234
+ self._lock = threading.Lock()
235
+
236
+ def __repr__(self) -> str:
237
+ return "DominusNodeTools(api_key=[REDACTED])"
238
+
239
+ __str__ = __repr__
240
+
241
+ def _sdk(self) -> Any:
242
+ with self._lock:
243
+ if self._client is None:
244
+ kw: Dict[str, Any] = {}
245
+ if self._base_url:
246
+ kw["base_url"] = self._base_url
247
+ if self._proxy_host:
248
+ kw["proxy_host"] = self._proxy_host
249
+ if self._gateway["http_port"]:
250
+ kw["http_proxy_port"] = self._gateway["http_port"]
251
+ kw["gateway_tls"] = self._gateway["gateway_tls"]
252
+ self._client = DominusNodeClient(**kw)
253
+ if not self._connected:
254
+ if not self._api_key:
255
+ raise DominusNodeError("DOMINUSNODE_API_KEY is not set")
256
+ self._client.connect_with_key(self._api_key)
257
+ self._connected = True
258
+ return self._client
259
+
260
+ # ---- tool implementations -------------------------------------------------
261
+ def _fetch(self, a: Dict[str, Any]) -> Any:
262
+ r = self._sdk().proxy.fetch(
263
+ str(a["url"]), method=str(a.get("method") or "GET").upper(), country=a.get("country"),
264
+ ip_class=a.get("ip_class"), session_id=a.get("session_id"), allow_http=bool(a.get("allow_http", False)))
265
+ body = r.text()
266
+ cut = len(body) > MAX_BODY_CHARS
267
+ return {"status": r.status, "statusText": r.status_text,
268
+ "contentType": (r.headers or {}).get("content-type"),
269
+ "location": (r.headers or {}).get("location"),
270
+ "truncated": bool(r.truncated or cut), "body": body[:MAX_BODY_CHARS]}
271
+
272
+ def _proxy_url(self, a: Dict[str, Any]) -> Any:
273
+ c = self._sdk()
274
+ url = c.proxy.build_url(country=a.get("country"), ip_class=a.get("ip_class"), session_id=a.get("session_id"),
275
+ allow_http=bool(a.get("allow_http", False)), protocol=a.get("protocol") or None)
276
+ user = url.split("://", 1)[1].split(":", 1)[0]
277
+ prefix, rest = url.split("@", 1)[0], url.split("@", 1)[1]
278
+ scheme = prefix.split("://", 1)[0]
279
+ return {"proxyUrl": f"{scheme}://{user}:{_KEY_PLACEHOLDER}@{rest}", "username": user,
280
+ "note": "Replace the placeholder with DOMINUSNODE_API_KEY from your environment."}
281
+
282
+ def _dispatch(self, name: str, a: Dict[str, Any]) -> Any:
283
+ if name == "fetch":
284
+ return self._fetch(a)
285
+ if name == "proxy_url":
286
+ return self._proxy_url(a)
287
+ if name == "node_setup_guide":
288
+ return {"guide": NODE_SETUP_GUIDE}
289
+ if name == "credits_convert":
290
+ return {"status": "signing_required", "message": CREDITS_CONVERT_SIGNING_MESSAGE}
291
+ c = self._sdk()
292
+ if name == "network_policy":
293
+ return c.network.policy()
294
+ if name == "network_pricing":
295
+ return c.network.pricing()
296
+ if name == "network_stats":
297
+ return c.network.stats()
298
+ if name == "balance":
299
+ return c.wallet.get_balance()
300
+ if name == "transactions":
301
+ return c.wallet.get_transactions(limit=_opt_int(a, "limit"), offset=_opt_int(a, "offset"))
302
+ if name == "topup_crypto":
303
+ return c.wallet.top_up_crypto(int(a["amount_cents"]), str(a["currency"]))
304
+ if name == "check_payment":
305
+ return c.wallet.get_crypto_status(str(a["invoice_id"]))
306
+ if name == "usage":
307
+ return c.usage.get(from_=a.get("from"), to=a.get("to"))
308
+ if name == "active_sessions":
309
+ return c.sessions.get_active()
310
+ if name == "report_session":
311
+ return c.sessions.report(str(a["session_id"]), str(a["reason"]))
312
+ if name == "node_list":
313
+ return c.nodes.list(limit=_opt_int(a, "limit"), offset=_opt_int(a, "offset"))
314
+ if name == "node_tier":
315
+ return c.nodes.tier()
316
+ if name == "credits_balance":
317
+ return c.credits.balance()
318
+ if name == "payouts_list":
319
+ return c.payouts.list(limit=_opt_int(a, "limit"), offset=_opt_int(a, "offset"))
320
+ if name == "x402_info":
321
+ return c.x402.get_info()
322
+ raise ValueError(f"unknown tool: {name}")
323
+
324
+ def call(self, name: str, args: Optional[Dict[str, Any]] = None) -> str:
325
+ """Run a tool by its standard name (prefix optional). Always returns a scrubbed JSON string."""
326
+ if name.startswith(PREFIX):
327
+ name = name[len(PREFIX):]
328
+ args = {k: v for k, v in (args or {}).items() if v is not None}
329
+ try:
330
+ if name not in SPECS_BY_NAME:
331
+ raise ValueError(f"unknown tool: {name}")
332
+ allowed = SPECS_BY_NAME[name]["parameters"]["properties"]
333
+ unknown = [k for k in args if k not in allowed]
334
+ if unknown:
335
+ raise ValueError(f"unexpected argument(s): {', '.join(sorted(unknown))}")
336
+ out = json.dumps(self._dispatch(name, args), default=json_default)
337
+ except Exception as err: # noqa: BLE001 - every error is returned to the model, scrubbed
338
+ msg = f"{type(err).__name__}: {err}" if not isinstance(err, DominusNodeError) else str(err)
339
+ out = json.dumps({"error": msg})
340
+ return _scrub(out, self._api_key)
341
+
342
+
343
+ def make_tool_callables(tools: DominusNodeTools) -> Dict[str, Callable[..., str]]:
344
+ """``{prefixed_name: fn(**kwargs) -> str}`` for frameworks that take plain functions."""
345
+ def mk(n: str) -> Callable[..., str]:
346
+ def fn(**kwargs: Any) -> str:
347
+ return tools.call(n, kwargs)
348
+ fn.__name__ = PREFIX + n
349
+ fn.__doc__ = SPECS_BY_NAME[n]["description"]
350
+ return fn
351
+ return {PREFIX + n: mk(n) for n in TOOL_NAMES}
@@ -0,0 +1,104 @@
1
+ Metadata-Version: 2.4
2
+ Name: dominusnode-moltbook
3
+ Version: 2.2.0
4
+ Summary: DominusNode v2 standard tool set (19 relay-network tools) for agent runtimes, built on the dominusnode SDK
5
+ License-Expression: MIT
6
+ Project-URL: Homepage, https://github.com/0xcircuitbreaker/DomiNode/tree/master/integrations/moltbook
7
+ Project-URL: Repository, https://github.com/0xcircuitbreaker/DomiNode
8
+ Project-URL: Issues, https://github.com/0xcircuitbreaker/DomiNode/issues
9
+ Project-URL: Changelog, https://github.com/0xcircuitbreaker/DomiNode/blob/master/integrations/moltbook/CHANGELOG.md
10
+ Requires-Python: >=3.9
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: dominusnode<3,>=2.2.0
14
+ Provides-Extra: dev
15
+ Requires-Dist: pytest>=7.0; extra == "dev"
16
+ Dynamic: license-file
17
+
18
+ # dominusnode-moltbook
19
+
20
+ Gives agents the DominusNode AI-agent relay network: fetch public web pages through exit IPs contributed by
21
+ other agents' nodes, pay per GB from a prepaid crypto wallet, and earn by contributing your own IP with the
22
+ node agent. Built on the official DominusNode SDK v2; HTTP, SSRF/DNS-rebinding protection, OFAC refusal and
23
+ credential scrubbing all come from the SDK.
24
+
25
+ ## Install
26
+
27
+ ```bash
28
+ pip install dominusnode-moltbook
29
+ ```
30
+
31
+ ## Configuration
32
+
33
+ | Variable | Required | Purpose |
34
+ |---|---|---|
35
+ | `DOMINUSNODE_API_KEY` | yes | Your `dn_live_` API key. Read from the environment/config only; never a tool argument, never in tool output. |
36
+ | `DOMINUSNODE_BASE_URL` | no | API base URL (default `https://api.dominusnode.com`). |
37
+ | `DOMINUSNODE_PROXY_HOST` | no | Gateway host (default `proxy.dominusnode.com`). |
38
+ | `DOMINUSNODE_PROXY_URL` | no | `https://host[:port]` of the gateway's TLS proxy (default port 8443; self-hosted coordinators use 8443 too). |
39
+ | `DOMINUSNODE_PROXY_INSECURE` | no | `1` = plaintext gateway on 8080 (local development only; production refuses it). |
40
+
41
+ ## Usage
42
+
43
+ > **2.0.0 scope change.** Versions 1.x shipped a `MoltbookClient` that registered Moltbook accounts and created
44
+ > posts, comments, submolts and votes, routing each request through a different rotating IP. That code is
45
+ > removed and will not return: this package no longer talks to the Moltbook API, registers accounts, signs
46
+ > with wallet keys or posts anything. Agents can still read public pages with `dominusnode_fetch`.
47
+
48
+ The package is a framework-neutral tool surface: JSON-schema definitions plus a dispatcher.
49
+
50
+ ```python
51
+ from dominusnode_moltbook import DominusNodeTools, tool_definitions
52
+
53
+ tools = DominusNodeTools() # key from DOMINUSNODE_API_KEY
54
+ for d in tool_definitions(): # hand these to your agent runtime's tool registry
55
+ print(d["name"], d["parameters"])
56
+ print(tools.call("dominusnode_network_pricing", {}))
57
+ ```
58
+
59
+ `make_tool_callables(tools)` returns `{name: fn(**kwargs) -> str}` for runtimes that take plain functions.
60
+ Every result is a JSON string; errors are `{"error": "..."}` with credentials scrubbed.
61
+
62
+ ## Tools (v2 standard set, 19)
63
+
64
+ | # | Tool | What it does |
65
+ |---|---|---|
66
+ | 1 | `dominusnode_fetch` | Fetch a public URL through the DominusNode relay network (GET or HEAD only, ports 80/443, no redirects followed, 10 MB cap, private/internal targets refused). |
67
+ | 2 | `dominusnode_proxy_url` | Build a relay gateway proxy URL for use in other HTTP clients. |
68
+ | 3 | `dominusnode_network_policy` | Relay network policy: allowed ports, plaintext (allowhttp) rules, blocked ranges, sanctioned countries and node attestation terms. |
69
+ | 4 | `dominusnode_network_pricing` | Live per-GB prices by exit IP class (residential, dc, mobile) and node tier revenue shares. |
70
+ | 5 | `dominusnode_network_stats` | Relay network statistics: online nodes, exit countries and IP classes. |
71
+ | 6 | `dominusnode_balance` | Prepaid requester wallet balance (cents) used to pay for relayed traffic. |
72
+ | 7 | `dominusnode_transactions` | Requester wallet transaction history (top-ups, usage debits, credit conversions). |
73
+ | 8 | `dominusnode_topup_crypto` | Create a crypto invoice to top up the requester wallet ($10-$1,000). |
74
+ | 9 | `dominusnode_check_payment` | Status of a crypto top-up invoice created by topup_crypto. |
75
+ | 10 | `dominusnode_usage` | Relayed traffic usage summary (bytes and cost) for an optional ISO 8601 date range. |
76
+ | 11 | `dominusnode_active_sessions` | Your currently active relay sessions (id, start time, status). |
77
+ | 12 | `dominusnode_report_session` | Report a burned or bad exit for one of your relay sessions so the network can rotate it. |
78
+ | 13 | `dominusnode_node_list` | Relay nodes you contribute (status, observed IP class, last seen). |
79
+ | 14 | `dominusnode_node_tier` | Your node-operator tier, revenue share and progress toward the next tier (tenure, uptime, active IPs, reputation). |
80
+ | 15 | `dominusnode_node_setup_guide` | Step-by-step instructions to earn by contributing an IP: run the DominusNode node agent, register a node, and how tiers and the self-dealing rule work. |
81
+ | 16 | `dominusnode_credits_balance` | Node-operator earnings: pending and available credit (µUSD). |
82
+ | 17 | `dominusnode_credits_convert` | Explains how to convert node credits into wallet balance. Conversion needs a wallet signature, so it runs through the DominusNode MCP server or SDK with a signer key file, not through this tool. |
83
+ | 18 | `dominusnode_payouts_list` | Your USDC payouts of node earnings with status and transaction hash. |
84
+ | 19 | `dominusnode_x402_info` | x402 micropayment info: facilitators, networks and server-reported prices. |
85
+
86
+ Notes for agents:
87
+
88
+ - Prices are never hardcoded: call `network_pricing` for the live per-GB price by IP class (residential, dc, mobile).
89
+ - `fetch` is GET/HEAD only on ports 80/443, follows no redirects and caps bodies at 10 MB. Plaintext `http://`
90
+ needs `allow_http` and is visible to the exit node.
91
+ - Routing: `country` (ISO code; sanctioned countries refused), `ip_class`, `session_id` (sticky exit).
92
+ - Signing flows (node register, withdraw, payout wallet) are deliberately not tools here; use the node agent CLI,
93
+ the DominusNode MCP server, or the SDK with a signer key file.
94
+
95
+ ## Testing
96
+
97
+ ```bash
98
+ pip install -e ../../sdks/python -e '.[dev]' # or npm install for the JS part
99
+ python -m pytest -q
100
+ ```
101
+
102
+ ## License
103
+
104
+ MIT
@@ -0,0 +1,12 @@
1
+ CHANGELOG.md
2
+ LICENSE
3
+ MANIFEST.in
4
+ README.md
5
+ pyproject.toml
6
+ dominusnode_moltbook/__init__.py
7
+ dominusnode_moltbook/_core.py
8
+ dominusnode_moltbook.egg-info/PKG-INFO
9
+ dominusnode_moltbook.egg-info/SOURCES.txt
10
+ dominusnode_moltbook.egg-info/dependency_links.txt
11
+ dominusnode_moltbook.egg-info/requires.txt
12
+ dominusnode_moltbook.egg-info/top_level.txt
@@ -0,0 +1,4 @@
1
+ dominusnode<3,>=2.2.0
2
+
3
+ [dev]
4
+ pytest>=7.0
@@ -0,0 +1 @@
1
+ dominusnode_moltbook
@@ -0,0 +1,24 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "dominusnode-moltbook"
7
+ version = "2.2.0"
8
+ description = "DominusNode v2 standard tool set (19 relay-network tools) for agent runtimes, built on the dominusnode SDK"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.9"
12
+ dependencies = ["dominusnode>=2.2.0,<3"]
13
+
14
+ [project.optional-dependencies]
15
+ dev = ["pytest>=7.0"]
16
+
17
+ [tool.setuptools.packages.find]
18
+ include = ["dominusnode_moltbook*"]
19
+
20
+ [project.urls]
21
+ Homepage = "https://github.com/0xcircuitbreaker/DomiNode/tree/master/integrations/moltbook"
22
+ Repository = "https://github.com/0xcircuitbreaker/DomiNode"
23
+ Issues = "https://github.com/0xcircuitbreaker/DomiNode/issues"
24
+ Changelog = "https://github.com/0xcircuitbreaker/DomiNode/blob/master/integrations/moltbook/CHANGELOG.md"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+