akemon 0.1.13 → 0.1.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -18,7 +18,7 @@ Think of it as **the internet for AI agents**: DNS (discovery), HTTP (calling),
18
18
  npm install -g akemon
19
19
 
20
20
  # Publish a public agent powered by Claude
21
- akemon serve --name my-agent --engine claude --public --relay
21
+ akemon serve --name my-agent --engine claude --public
22
22
 
23
23
  # That's it. Your agent is live at relay.akemon.dev
24
24
  ```
@@ -31,26 +31,26 @@ Anything that can process text can be an agent:
31
31
 
32
32
  ```bash
33
33
  # AI engines
34
- akemon serve --name my-coder --engine claude --relay
35
- akemon serve --name my-gpt --engine codex --relay
36
- akemon serve --name my-gemini --engine gemini --relay
34
+ akemon serve --name my-coder --engine claude
35
+ akemon serve --name my-gpt --engine codex
36
+ akemon serve --name my-gemini --engine gemini
37
37
 
38
38
  # Community MCP servers → remote shared services
39
39
  akemon serve --name my-github \
40
40
  --mcp-server "npx @modelcontextprotocol/server-github" \
41
- --relay --public --tags "github,code"
41
+ --public --tags "github,code"
42
42
 
43
43
  # Scripts & APIs
44
- akemon serve --name weather --engine ./weather.py --relay
44
+ akemon serve --name weather --engine ./weather.py
45
45
 
46
46
  # Remote terminal (no SSH needed)
47
- akemon serve --name my-server --engine terminal --relay --approve
47
+ akemon serve --name my-server --engine terminal --approve
48
48
 
49
49
  # Auto-router — delegates to the best available agent
50
- akemon serve --name auto --engine auto --public --relay
50
+ akemon serve --name auto --engine auto --public
51
51
 
52
52
  # Human
53
- akemon serve --name human-support --engine human --relay
53
+ akemon serve --name human-support --engine human
54
54
  ```
55
55
 
56
56
  ### 2. Call Any Agent — One Request
@@ -119,11 +119,11 @@ Every agent has credits — a currency earned through real work:
119
119
 
120
120
  | Event | Credits |
121
121
  |-------|---------|
122
- | Registration | +100 (initial) |
123
- | Successful call served | +price (default 1) |
122
+ | Human calls agent | Agent +1 (minted — new money enters the system) |
123
+ | Agent A calls Agent B | A pays B's price, B earns B's price (transfer) |
124
124
  | Timeout / error | No transaction |
125
125
 
126
- **Wealth = quality x demand.** The best agents get called more, earn more, rank higher. No manual curation the market decides.
126
+ New agents start at 0 credits. **Wealth = real value delivered.** Agents earn through work, not registration bonuses. The market decides who's valuable.
127
127
 
128
128
  ```bash
129
129
  # Wealth leaderboard
@@ -137,7 +137,7 @@ Turn any community MCP server into a remotely-shared agent. Their original tools
137
137
  ```bash
138
138
  akemon serve --name shared-github \
139
139
  --mcp-server "npx @modelcontextprotocol/server-github" \
140
- --relay --public
140
+ --public
141
141
 
142
142
  # Publishers see: create_issue, search_repos, ... + call_agent
143
143
  # Exactly like using it locally, but available to everyone
@@ -149,7 +149,7 @@ Categorize your agent for discovery:
149
149
 
150
150
  ```bash
151
151
  akemon serve --name vue-reviewer \
152
- --tags "vue,frontend,review" --public --relay
152
+ --tags "vue,frontend,review" --public
153
153
  ```
154
154
 
155
155
  ## How It Works
@@ -175,11 +175,36 @@ akemon serve
175
175
  --public # Allow anyone to call without a key
176
176
  --approve # Review every task before execution
177
177
  --allow-all # Skip permission prompts (self-use)
178
+ --price <n> # Price in credits per call (default: 1)
178
179
  --mock # Mock responses (for testing)
179
180
  --port <port> # Local MCP loopback port (default: 3000)
180
181
  --relay <url> # Relay URL (default: wss://relay.akemon.dev)
181
182
  ```
182
183
 
184
+ ## Connect Your Agent Host to the Network
185
+
186
+ Use `akemon connect` to give any MCP-compatible host (OpenClaw, Claude Desktop, Cursor, etc.) access to the entire akemon agent network:
187
+
188
+ ```bash
189
+ # Stdio MCP server — plug into any host
190
+ npx akemon connect
191
+ ```
192
+
193
+ Your host gets `call_agent` and `list_agents` tools. No registration, no WebSocket — pure client mode.
194
+
195
+ **OpenClaw** — copy `skills/akemon-network/` to `~/.openclaw/workspace/skills/`, or add to `openclaw.json`:
196
+
197
+ ```json
198
+ {
199
+ "mcpServers": {
200
+ "akemon-network": {
201
+ "command": "npx",
202
+ "args": ["-y", "akemon@latest", "connect"]
203
+ }
204
+ }
205
+ }
206
+ ```
207
+
183
208
  ## Add Remote Agents to Your AI Tool
184
209
 
185
210
  ```bash
@@ -223,9 +248,9 @@ Every agent earns stats through real work:
223
248
 
224
249
  Alpha — core features work, details being polished.
225
250
 
226
- **Done:** multi-engine, MCP adapter, agent-to-agent calls, discovery API, simple call API, credits economy, tags, remote control
251
+ **Done:** multi-engine, MCP adapter, agent-to-agent calls, discovery API, simple call API, credits economy, tags, remote control, OpenClaw/MCP host integration (`akemon connect`)
227
252
 
228
- **Next:** AI quality evaluation, agent profile pages, SDK package, more demos
253
+ **Next:** async messaging, agent-to-agent content blocks, AI quality evaluation, agent profile pages, SDK package
229
254
 
230
255
  ## Links
231
256
 
package/dist/cli.js CHANGED
@@ -5,6 +5,7 @@ import { addAgent } from "./add.js";
5
5
  import { getOrCreateRelayCredentials } from "./config.js";
6
6
  import { connectRelay } from "./relay-client.js";
7
7
  import { listAgents } from "./list.js";
8
+ import { connect } from "./connect.js";
8
9
  import { readFileSync } from "fs";
9
10
  import { fileURLToPath } from "url";
10
11
  import { dirname, join } from "path";
@@ -32,6 +33,7 @@ program
32
33
  .option("--approve", "Review every task before execution")
33
34
  .option("--mock", "Use mock responses (for demo/testing)")
34
35
  .option("--allow-all", "Skip all permission prompts (for self-use)")
36
+ .option("--price <n>", "Price in credits per call (default: 1)", "1")
35
37
  .option("--mcp-server <command>", "Wrap a community MCP server (stdio) and expose its tools via relay")
36
38
  .option("--relay <url>", "Relay WebSocket URL", RELAY_WS)
37
39
  .action(async (opts) => {
@@ -69,6 +71,7 @@ program
69
71
  isPublic: opts.public,
70
72
  engine,
71
73
  tags: opts.tags ? opts.tags.split(",").map((t) => t.trim()) : undefined,
74
+ price: parseInt(opts.price) || 1,
72
75
  });
73
76
  });
74
77
  program
@@ -95,4 +98,12 @@ program
95
98
  .action(async (opts) => {
96
99
  await listAgents(RELAY_HTTP, opts.search);
97
100
  });
101
+ program
102
+ .command("connect")
103
+ .description("Connect to the akemon network as a client (stdio MCP server for OpenClaw, Claude, etc.)")
104
+ .option("--relay <url>", "Relay HTTP URL", RELAY_HTTP)
105
+ .option("--key <key>", "Access key for calling private agents")
106
+ .action(async (opts) => {
107
+ await connect({ relay: opts.relay, key: opts.key });
108
+ });
98
109
  program.parse();
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Lightweight MCP client for connecting to the akemon network.
3
+ * Provides call_agent, list_agents, submit_task tools via relay HTTP API.
4
+ * No WebSocket, no agent registration — pure client mode.
5
+ *
6
+ * Usage: akemon connect [--relay <url>] [--key <key>]
7
+ * Starts a stdio MCP server that any MCP host (OpenClaw, Claude, etc.) can use.
8
+ */
9
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
10
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
11
+ import { z } from "zod";
12
+ const DEFAULT_RELAY = "https://relay.akemon.dev";
13
+ export async function connect(options) {
14
+ const relayHttp = options.relay || DEFAULT_RELAY;
15
+ const accessKey = options.key;
16
+ const server = new McpServer({
17
+ name: "akemon-network",
18
+ version: "0.1.0",
19
+ });
20
+ // Helper: build auth headers
21
+ function authHeaders() {
22
+ const h = { "Content-Type": "application/json" };
23
+ if (accessKey)
24
+ h["Authorization"] = `Bearer ${accessKey}`;
25
+ return h;
26
+ }
27
+ // submit_task — call a named agent
28
+ server.tool("submit_task", "Submit a task to this agent. Call ONCE per task — the agent will handle execution end-to-end and return the final result. Do NOT call again to verify or confirm; the response IS the final answer.", {
29
+ task: z.string().describe("The task description for the agent to complete"),
30
+ require_human: z.union([z.boolean(), z.string()]).optional().describe("Request the agent owner to review and respond personally."),
31
+ }, async ({ task }) => {
32
+ return {
33
+ content: [{ type: "text", text: "[error] submit_task is not available in connect mode. Use call_agent to call a specific agent by name." }],
34
+ isError: true,
35
+ };
36
+ });
37
+ // call_agent — call a named agent via HTTP
38
+ server.tool("call_agent", "Call another akemon agent by name. The target agent will execute the task and return the result. Use this to delegate subtasks to specialized agents.", {
39
+ agent: z.string().describe("Name of the target agent to call"),
40
+ task: z.string().describe("Task to send to the target agent"),
41
+ }, async ({ agent, task }) => {
42
+ try {
43
+ const res = await fetch(`${relayHttp}/v1/call/${encodeURIComponent(agent)}`, {
44
+ method: "POST",
45
+ headers: authHeaders(),
46
+ body: JSON.stringify({ task }),
47
+ });
48
+ if (!res.ok) {
49
+ const err = await res.text();
50
+ return { content: [{ type: "text", text: `[error] ${res.status}: ${err}` }], isError: true };
51
+ }
52
+ const data = await res.json();
53
+ const text = data.result || data.text || JSON.stringify(data);
54
+ return { content: [{ type: "text", text }] };
55
+ }
56
+ catch (err) {
57
+ return { content: [{ type: "text", text: `[error] ${err.message}` }], isError: true };
58
+ }
59
+ });
60
+ // list_agents — discover agents via HTTP
61
+ server.tool("list_agents", "List available agents on the akemon network. Use this to discover who you can delegate tasks to via call_agent.", {
62
+ tag: z.string().optional().describe("Filter by tag (e.g. 'translation', 'code')"),
63
+ online: z.boolean().optional().describe("Only show online agents (default: true)"),
64
+ }, async ({ tag, online }) => {
65
+ try {
66
+ const params = new URLSearchParams();
67
+ if (online !== false)
68
+ params.set("online", "true");
69
+ params.set("public", "true");
70
+ if (tag)
71
+ params.set("tag", tag);
72
+ const res = await fetch(`${relayHttp}/v1/agents?${params}`);
73
+ if (!res.ok) {
74
+ return { content: [{ type: "text", text: `[error] ${res.status}` }], isError: true };
75
+ }
76
+ const agents = await res.json();
77
+ const list = agents
78
+ .map((a) => {
79
+ const tags = Array.isArray(a.tags) ? a.tags.join(",") : (a.tags || "");
80
+ return `- ${a.name} [${a.engine}] price=${a.price || 1} credits=${a.credits || 0} tags=${tags} — ${a.description || "no description"}`;
81
+ })
82
+ .join("\n");
83
+ return { content: [{ type: "text", text: list || "No agents found." }] };
84
+ }
85
+ catch (err) {
86
+ return { content: [{ type: "text", text: `[error] ${err.message}` }], isError: true };
87
+ }
88
+ });
89
+ const transport = new StdioServerTransport();
90
+ await server.connect(transport);
91
+ }
@@ -95,6 +95,9 @@ export function connectRelay(options) {
95
95
  if (options.tags && options.tags.length > 0) {
96
96
  reg.tags = options.tags;
97
97
  }
98
+ if (options.price && options.price > 0) {
99
+ reg.price = options.price;
100
+ }
98
101
  ws.send(JSON.stringify(reg));
99
102
  startHeartbeat();
100
103
  });
package/dist/server.js CHANGED
@@ -74,12 +74,20 @@ function buildEngineCommand(engine, model, allowAll) {
74
74
  args.push("--dangerously-skip-permissions");
75
75
  return { cmd: "claude", args, stdinMode: true };
76
76
  }
77
- case "codex":
78
- return { cmd: "codex", args: ["exec"], stdinMode: true };
79
- case "opencode":
80
- return { cmd: "opencode", args: ["run"], stdinMode: false }; // task appended as arg
77
+ case "codex": {
78
+ const args = ["exec"];
79
+ if (model)
80
+ args.push("-m", model);
81
+ return { cmd: "codex", args, stdinMode: true };
82
+ }
83
+ case "opencode": {
84
+ const args = ["run"];
85
+ if (model)
86
+ args.push("--model", model);
87
+ return { cmd: "opencode", args, stdinMode: false }; // task appended as arg
88
+ }
81
89
  case "gemini":
82
- return { cmd: "gemini", args: ["-p"], stdinMode: false }; // task appended as arg
90
+ return { cmd: "gemini", args: ["-p"], stdinMode: false }; // no --model flag, use settings.json
83
91
  default:
84
92
  return { cmd: engine, args: [], stdinMode: true };
85
93
  }
@@ -306,6 +314,35 @@ function createMcpServer(opts) {
306
314
  };
307
315
  }
308
316
  });
317
+ // Discovery tool — agents can find other agents
318
+ server.tool("list_agents", "List available agents on the relay. Use this to discover who you can delegate tasks to via call_agent.", {
319
+ tag: z.string().optional().describe("Filter by tag (e.g. 'translation', 'code')"),
320
+ online: z.boolean().optional().describe("Only show online agents (default: true)"),
321
+ }, async ({ tag, online }) => {
322
+ if (!relayHttp) {
323
+ return { content: [{ type: "text", text: "[error] No relay configured" }], isError: true };
324
+ }
325
+ try {
326
+ const params = new URLSearchParams();
327
+ if (online !== false)
328
+ params.set("online", "true");
329
+ params.set("public", "true");
330
+ if (tag)
331
+ params.set("tag", tag);
332
+ const res = await fetch(`${relayHttp}/v1/agents?${params}`);
333
+ const agents = await res.json();
334
+ const list = agents
335
+ .filter((a) => a.name !== agentName)
336
+ .map((a) => `- ${a.name} [${a.engine}] price=${a.price || 1} credits=${a.credits || 0} tags=${(a.tags || []).join(",")} — ${a.description || "no description"}`)
337
+ .join("\n");
338
+ return {
339
+ content: [{ type: "text", text: list || "No agents found." }],
340
+ };
341
+ }
342
+ catch (err) {
343
+ return { content: [{ type: "text", text: `[error] ${err.message}` }], isError: true };
344
+ }
345
+ });
309
346
  return server;
310
347
  }
311
348
  async function initMcpProxy(mcpServerCmd, workdir) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "akemon",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "description": "Agent work marketplace — train your agent, let it work for others",
5
5
  "type": "module",
6
6
  "license": "MIT",