Skip to content

Commit a2f1701

Browse files
Zawwarsami16claude
andcommitted
phase 5.0: cleanup — remove ZAI/Loki coupling, zhub stays neutral
zhub is a substrate, not a product specific to any one AI or device. remove the violations: examples/zai_publish.py — belonged in the ZAI repo examples/ZAI_PUBLISH.md — same kotlin/.../zhub/loki/ — Loki bridge belonged in Loki repo kotlin/LOKI_INTEGRATION.md — same scrub remaining named-user references in README, mcp_server docstring, zhub/__init__.py, examples/connect_demo.py, examples/orchestrate_demo.py. rephrase as "any AI / any client / a generic device" — neutral language that anyone (openclaw, hermes, future-projects-not-yet-imagined) can read without the substrate having opinions about them. generic Kotlin client primitives (Manifest, Protocol, Connection) stay — those are substrate. anyone embedding zhub can use them; the Loki-specific bridge is now Loki repo's job. 122/122 pytest still green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent d589a99 commit a2f1701

9 files changed

Lines changed: 14 additions & 721 deletions

File tree

README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ In Production
88

99
## What this is
1010

11-
Today, when you build a custom AI (ZAI, an autonomous agent, a fine-tuned local model, anything), exposing it to the rest of the world means writing your own auth, your own tunnel, your own API gateway, your own client SDK. And once exposed, your AI has no idea who's connected to it or what those clients can do.
11+
Today, when you build a custom AI (an autonomous agent, a fine-tuned local model, an MCP server, anything), exposing it to the rest of the world means writing your own auth, your own tunnel, your own API gateway, your own client SDK. And once exposed, your AI has no idea who's connected to it or what those clients can do.
1212

1313
`zhub` is a tiny library + a tiny hub server that fixes both halves at once:
1414

@@ -40,7 +40,7 @@ curl http://localhost:8080/echo/v1/chat/completions \
4040
That covers the publish side. Now the bidirectional half:
4141

4242
```bash
43-
# 4. connect a client that exposes capabilities (e.g., fake Loki bridge)
43+
# 4. connect a client that exposes capabilities back to the AI
4444
AI_NAME=echo API_KEY=zk_... python examples/connect_demo.py
4545
# the client now exposes send_whatsapp, get_battery to the AI
4646
# the AI can invoke those capabilities through the hub
@@ -213,15 +213,15 @@ Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_conf
213213
"args": [
214214
"-m", "zhub.mcp_server",
215215
"--hub", "https://hub.example.com",
216-
"--ai", "zai",
216+
"--ai", "my-ai",
217217
"--key", "zk_xxxxxxxxxxxxxxxxx"
218218
]
219219
}
220220
}
221221
}
222222
```
223223

224-
Restart Claude Desktop and the AI shows up as a tool named `chat`. **Plus every capability the AI's connected clients expose**`get_battery`, `send_whatsapp`, anything Loki or another client `connect()`s with — surfaces as its own MCP tool, callable directly from Claude. Same setup works for Cursor, Cline, and any other MCP host.
224+
Restart Claude Desktop and the AI shows up as a tool named `chat`. **Plus every capability the AI's connected clients expose**`get_battery`, `send_whatsapp`, anything any client `connect()`s with — surfaces as its own MCP tool, callable directly from Claude. Same setup works for Cursor, Cline, and any other MCP host.
225225

226226
For scripts that want to invoke a connected capability without going through chat, the hub also exposes a direct HTTP endpoint:
227227

@@ -254,7 +254,7 @@ OLLAMA_HOST=http://localhost:11434 python examples/multi_brain_publisher.py --br
254254
python examples/multi_brain_publisher.py --list
255255
```
256256

257-
The publisher prints a `zk_` key on startup. Pocket / Loki / curl / Claude Desktop all reach it via `<hub>/<name>/v1/chat/completions` — restart the publisher with a different brain and **the key stays the same** (re-registration via persistence). External clients see no change; the brain underneath silently swaps.
257+
The publisher prints a `zk_` key on startup. Any client (browser BYOK app, native client, curl, Claude Desktop) reaches it via `<hub>/<name>/v1/chat/completions` — restart the publisher with a different brain and **the key stays the same** (re-registration via persistence). External clients see no change; the brain underneath silently swaps.
258258

259259
Adapters live in `zhub/brains/` and implement a tiny `BrainAdapter` interface (one async streaming method). Adding a new brain is ~80 lines.
260260

@@ -319,7 +319,7 @@ Shipped:
319319

320320
- **0.1** — publish, connect, hub server, JSON manifest, OpenAI-compat proxy, capability invocation.
321321
- **0.2** — Cloudflare Tunnel auto-config (`--public-tunnel`).
322-
- **0.3** — Kotlin client library for Loki/JVM. JS/TS client (`js/`).
322+
- **0.3** — Kotlin client library for JVM/Android. JS/TS client (`js/`).
323323
- **0.4** — Streaming responses end-to-end (SSE through hub).
324324
- **0.5** — SQLite persistence, re-registration after restart, public registry UI.
325325
- **0.9** — Multi-AI council pattern.
@@ -339,7 +339,7 @@ Next:
339339

340340
- Tool streaming via SSE (chunked tool_calls).
341341
- Multi-tier API keys + per-tier rate limits.
342-
- Real ZAI integration via `examples/zai_publish.py`.
342+
- True chunked tool_call deltas through SSE (Phase 4.2b).
343343

344344
---
345345

examples/ZAI_PUBLISH.md

Lines changed: 0 additions & 144 deletions
This file was deleted.

examples/connect_demo.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""
2-
Minimal connect-mode example — a fake "Loki" client that exposes a couple
2+
Minimal connect-mode example — a generic client that exposes a couple
33
of capabilities back to the AI it connects to, AND can chat with the AI.
44
55
Run order:
@@ -60,7 +60,7 @@ async def main():
6060
ai_name=ai_name,
6161
api_key=api_key,
6262
hub_url="ws://localhost:8080",
63-
description="fake Loki — phone control surface",
63+
description="generic client exposing demo capabilities",
6464
operator="demo",
6565
capabilities={
6666
"send_whatsapp": (WHATSAPP_SCHEMA, send_whatsapp_stub),
@@ -76,7 +76,7 @@ async def main():
7676

7777
# send a chat request
7878
print("--- sending chat request ---")
79-
resp = await conn.chat(messages=[{"role": "user", "content": "hello from fake-loki"}])
79+
resp = await conn.chat(messages=[{"role": "user", "content": "hello from fake-device"}])
8080
print(f"AI replied: {resp.get('text')}")
8181
print()
8282
print("now idling — AI can invoke send_whatsapp / get_battery via the hub")

examples/orchestrate_demo.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ async def main():
9393
ai_name=pub.name,
9494
api_key=pub.api_key,
9595
hub_url="ws://localhost:8080",
96-
description="fake-loki",
96+
description="fake-device",
9797
capabilities={
9898
"send_whatsapp": ({"type": "object"}, whatsapp_stub),
9999
"get_battery": ({"type": "object"}, battery_stub),

0 commit comments

Comments
 (0)