Skip to content

Commit 9330941

Browse files
Zawwarsami16claude
andcommitted
phase 13.0: public release polish — CONTRIBUTING + CHANGELOG + SECURITY + Dockerfile + 0.2.0
new top-level files: CONTRIBUTING.md — how to set up dev env, propose changes, add a brain adapter (with template using shared _openai_compat helper), where the design conversations live (specs/) CHANGELOG.md — distilled phase history. 0.1.0 (initial) → 0.2.0 (8 brains, exposures, MCP triple, dashboard, tool streaming, federation, entity layer, dynamics) SECURITY.md — disclosure policy (email zawwarsami16@gmail.com), in-scope / out-of-scope, hardening defaults already in place (auth on every endpoint, hashed keys, ed25519 signing, rate limit, schema validation, loop prevention) Dockerfile rewritten: - multi-stage build for smaller final image - includes [server,brains] extras (the multi-brain publisher works) - non-root user (uid 1000, /home/zhub) - HEALTHCHECK against /healthz every 30s - default --db /data/zhub.db so `docker run -v zhub-data:/data` gives persistence out of the box - usage docs inline at the top pyproject.toml: - version 0.1.0 → 0.2.0 (12 phases of substrate work since initial) - status Alpha → Beta - Python 3.13 added to classifiers - added Topics: Internet/HTTP, Communications/Chat, Framework: AsyncIO - added keywords: llm, claude, ollama, groq - new console_scripts entry: `zhub = zhub.__main__:main` so `zhub up` works directly after install (the long form `python -m zhub up` still works too) zhub/__init__.py: __version__ bumped 0.1.0 → 0.2.0 to match. README: - test badge updated 141/141 → 164 + 13 - new badges: brains-8, version-0.2.0 - quickstart shows `zhub up` (installed script) with note about the `python -m zhub up` equivalent 164/164 pytest still green; no functional change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent a6878fc commit 9330941

7 files changed

Lines changed: 216 additions & 11 deletions

File tree

CHANGELOG.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Changelog
2+
3+
All notable changes to zhub. Versions follow [SemVer](https://semver.org/).
4+
5+
## [0.2.0] — 2026-05-10
6+
7+
### Added
8+
- **8 brain adapters** — Ollama, Groq, OpenAI, Cerebras, Anthropic, Together, Mistral, Cohere. Streaming-first; auto-detect via env vars; swap with one CLI flag.
9+
- **`python -m zhub up`** — one-command bring-up (hub + optional Cloudflare tunnel + brain publisher), prints `URL:` and `KEY:` ready to paste into any OpenAI-compat client.
10+
- **`python -m zhub doctor`** — environment + dependency + creds diagnostic.
11+
- **`python -m zhub.mcp_server`** — exposes any zhub-published AI as an MCP stdio server (Claude Desktop / Cursor / Cline). Implements full MCP triple: tools, **resources, prompts**.
12+
- **Capability-only WebSocket exposures** — devices register tools without pairing to any specific AI; any registered publisher can invoke via `POST /exposures/<id>/invoke`.
13+
- **Tool calls** — auto-resolved against connected capabilities + exposures, parallel resolution via `asyncio.gather`, JSON-Schema arg validation, audit log in `usage.tool_results`.
14+
- **Streaming tool calls**`X-Zhub-Stream-Tools: auto` resolves and continues the SSE stream; `pre-resolve` buffers; default passes deltas through verbatim for native OpenAI clients.
15+
- **Federation across hubs** — cross-hub HTTP chat proxy + cross-hub WebSocket connect tunnel, transparent to clients.
16+
- **Self-knowledge entity layer**`GET /entity` ships zhub's own routes/errors/patterns/install/up/paths recipes; operators extend per-deployment via `POST /entity/extend`. Every 4xx/5xx response carries `X-Zhub-Entity-Hint` pointing at the relevant recipe.
17+
- **Operator dashboard at `/`** — futuristic glassmorphism UI with live SVG traffic flow visualization (particles per request, color-coded by status), publisher cards with sparklines, exposure tiles, recent-requests feed, federation peers. Auto-refresh 2s.
18+
- **Production observability**`/metrics` JSON snapshot with per-AI request count, total/avg/max/p50/p95/p99 latency. Structured access logs at `zhub.access` logger.
19+
- **Cloudflare named tunnel support**`python -m zhub up --tunnel-name <name>` for stable URLs across restarts.
20+
- **`docs/DEPLOY.md`** — $5 VPS deployment walkthrough with systemd unit files for hub + named tunnel.
21+
- **Multi-language clients** — JS/TS (`@zawwarsami/zhub`), Kotlin/JVM, Python all interoperate against the same hub.
22+
23+
### Changed
24+
- Hub neutrality: removed all product-specific coupling. The substrate doesn't know about specific AIs or devices; bridges to specific products live in those products' own repos.
25+
- README rewritten as a public-facing professional doc with hard performance numbers, mermaid architecture diagram, comparison matrix, brain pricing table, multi-language client matrix.
26+
27+
### Test surface
28+
- 164 pytest (Python 3.10/3.11/3.12 in CI)
29+
- 13 node:test (JS client)
30+
31+
## [0.1.0] — 2026-05-08
32+
33+
Initial release.
34+
35+
### Added
36+
- `publish()` and `connect()` primitives over WebSocket
37+
- Hub server (FastAPI + WebSocket multiplex)
38+
- OpenAI-compatible chat completions endpoint per published AI
39+
- SQLite persistence for publisher records
40+
- ed25519 signed manifests with key pinning
41+
- Cloudflare Tunnel auto-config (`--public-tunnel`)
42+
- Bidirectional invocation: AI calls back into connected clients via `pub.invoke()`
43+
- Sliding-window rate limiting per api_key
44+
- Read-only federation via `ZHUB_PEERS` env

CONTRIBUTING.md

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Contributing to zhub
2+
3+
Thanks for considering a contribution. zhub is intentionally small: each file does one thing, the test bar is high, and the public surface stays neutral. Keeping it that way is the contribution.
4+
5+
## Setup
6+
7+
```bash
8+
git clone https://github.com/Zawwarsami16/zhub
9+
cd zhub
10+
python3 -m venv .venv && source .venv/bin/activate
11+
pip install -e '.[server,dev,brains]'
12+
python -m zhub doctor # verify install
13+
pytest # 164 tests, ~80s
14+
```
15+
16+
For the JS client:
17+
18+
```bash
19+
cd js
20+
npm install
21+
npm test # 13 tests
22+
```
23+
24+
## How to propose a change
25+
26+
| Change type | Path |
27+
|---|---|
28+
| Bugfix or small refactor | open a PR with the diff + a regression test |
29+
| New feature, brain adapter, primitive | open an issue first (or a `docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md` PR) so the design is reviewable before implementation |
30+
| Documentation | direct PR is fine |
31+
32+
## Code rules
33+
34+
- **Test-driven.** Every behavior change ships with a test. If you add a new file under `zhub/`, there's a matching `tests/test_<name>.py`.
35+
- **Substrate, not opinion.** zhub knows nothing about your specific AI, your devices, or your business logic. Don't add product-specific bridges — those go in their own repos and consume zhub via `publish()` / `connect()` / `expose()`.
36+
- **No new top-level deps without justification.** The optional-extras pattern (`[server]`, `[crypto]`, `[brains]`) handles most cases. Hot path stays import-light.
37+
- **Async-first.** Hub-side code is asyncio. Sync work belongs in `to_thread` or its own subprocess.
38+
- **One-line comments only when the *why* is non-obvious.** Self-documenting names beat narration.
39+
40+
## Adding a brain adapter
41+
42+
Most hosted LLM providers speak OpenAI-compat. Use the shared helper:
43+
44+
```python
45+
# zhub/brains/<provider>.py
46+
from ._openai_compat import probe_openai_compat, stream_openai_compat
47+
from .base import BrainAdapter, ChatChunk
48+
import httpx, os
49+
50+
_BASE_URL = "https://api.<provider>.com/v1"
51+
_DEFAULT_MODEL = "..."
52+
53+
class <Provider>Adapter(BrainAdapter):
54+
name = "<provider>"
55+
label = "<Display Name>"
56+
# ... __init__, try_init using probe_openai_compat, stream delegating to stream_openai_compat
57+
```
58+
59+
Then register in `zhub/brains/__init__.py` REGISTRY (priority order matters for `detect()`) and add `tests/test_brains_<provider>.py` with the same monkeypatch + fake-stream pattern as the existing adapter tests.
60+
61+
For non-OpenAI shapes (e.g. Cohere), copy `zhub/brains/cohere.py` as a template.
62+
63+
## Running the live demo against your branch
64+
65+
```bash
66+
GROQ_API_KEY=gsk_... python -m zhub up
67+
# → URL + KEY
68+
```
69+
70+
Open `http://localhost:8080/` in a browser to see the dashboard. Generate traffic with:
71+
72+
```bash
73+
curl -s http://localhost:8080/healthz
74+
curl -s -X POST http://localhost:8080/me/v1/chat/completions \
75+
-H "Authorization: Bearer zk_..." \
76+
-d '{"messages":[{"role":"user","content":"hi"}]}'
77+
```
78+
79+
Particles fly through the live SVG flow on the dashboard for each request.
80+
81+
## Where the design conversations live
82+
83+
`docs/superpowers/specs/` has the design doc for every shipped phase. `docs/superpowers/plans/` has the TDD implementation plans. Walking through a few specs is the fastest way to understand how decisions were made.
84+
85+
## License
86+
87+
By contributing, you agree your contributions will be licensed under the MIT License.

Dockerfile

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,30 @@
1-
FROM python:3.12-slim
1+
# syntax=docker/dockerfile:1.6
2+
# zhub — multi-stage container build
3+
# Build: docker build -t zhub .
4+
# Run: docker run -p 8080:8080 -e GROQ_API_KEY=gsk_... zhub
5+
# With persistence: -v zhub-data:/data and pass --db /data/zhub.db
26

3-
WORKDIR /app
7+
FROM python:3.12-slim AS builder
8+
WORKDIR /build
49
COPY pyproject.toml README.md LICENSE ./
510
COPY zhub/ ./zhub/
11+
RUN pip install --no-cache-dir --target=/install '.[server,brains]'
612

7-
RUN pip install --no-cache-dir '.[server]'
13+
FROM python:3.12-slim AS runtime
14+
WORKDIR /app
15+
COPY --from=builder /install /usr/local/lib/python3.12/site-packages
16+
COPY zhub/ ./zhub/
17+
18+
# Non-root user for runtime
19+
RUN useradd --create-home --uid 1000 zhub && \
20+
mkdir -p /data && chown zhub:zhub /data
21+
USER zhub
822

923
EXPOSE 8080
10-
CMD ["python", "-m", "zhub.server", "--host", "0.0.0.0", "--port", "8080"]
24+
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
25+
CMD python -c "import urllib.request,sys; \
26+
sys.exit(0 if urllib.request.urlopen('http://127.0.0.1:8080/healthz', timeout=2).status == 200 else 1)"
27+
28+
CMD ["python", "-m", "zhub.server", \
29+
"--host", "0.0.0.0", "--port", "8080", \
30+
"--db", "/data/zhub.db"]

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
[![CI](https://github.com/Zawwarsami16/zhub/actions/workflows/ci.yml/badge.svg)](https://github.com/Zawwarsami16/zhub/actions/workflows/ci.yml)
88
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
99
[![Python 3.10+](https://img.shields.io/badge/python-3.10+-3776AB.svg)](https://www.python.org/)
10-
[![Tests](https://img.shields.io/badge/tests-141%2F141-brightgreen)](#tests)
10+
[![Tests](https://img.shields.io/badge/tests-164%20%2B%2013-brightgreen)](#tests)
11+
[![Brains](https://img.shields.io/badge/brains-8-cyan)](#performance)
12+
[![Version](https://img.shields.io/badge/version-0.2.0-orange)](CHANGELOG.md)
1113

1214
</div>
1315

@@ -18,9 +20,11 @@
1820
```bash
1921
git clone https://github.com/Zawwarsami16/zhub && cd zhub
2022
pip install -e '.[server,brains]'
21-
GROQ_API_KEY=gsk_... python -m zhub up
23+
GROQ_API_KEY=gsk_... zhub up
2224
```
2325

26+
(`zhub up` is the installed CLI; `python -m zhub up` is the equivalent module form when the script isn't on PATH.)
27+
2428
Output:
2529

2630
```

SECURITY.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Security Policy
2+
3+
## Reporting a vulnerability
4+
5+
If you find a security issue in zhub — credential exposure, auth bypass, validation skip, or anything else that lets an unauthorized caller act on a hub or a connected publisher — **please don't open a public issue**.
6+
7+
Instead, email **zawwarsami16@gmail.com** with:
8+
9+
- A description of the issue
10+
- Steps to reproduce
11+
- The version / commit you tested against
12+
- Your suggested mitigation (if any)
13+
14+
You'll get a response within 48 hours. Confirmed vulnerabilities are patched on `main` and noted in `CHANGELOG.md` once a fix is merged.
15+
16+
## Scope
17+
18+
In scope:
19+
- The Python hub (`zhub/server.py`) — auth, validation, rate limiting, federation, tool resolution, capability invocation
20+
- The Python publisher / connection / exposure SDK (`zhub/client.py`)
21+
- The MCP server bridge (`zhub/mcp_server.py`)
22+
- Brain adapters (`zhub/brains/`) when bugs allow injection or credential leakage
23+
- The JS / Kotlin clients
24+
25+
Out of scope:
26+
- Brain providers' own infrastructure (Groq, OpenAI, Anthropic, etc.) — report to them
27+
- Cloudflare Tunnel — report to Cloudflare
28+
- Operator misconfiguration (e.g., running the hub without `--db` and complaining about lost keys)
29+
30+
## Hardening defaults already in place
31+
32+
- Bearer-key auth required on every chat / invoke / extend endpoint
33+
- API keys stored hashed in SQLite (raw key returned to publisher exactly once at registration)
34+
- ed25519 signature verification + key pinning on signed manifests
35+
- Sliding-window rate limiting per api_key
36+
- JSON-Schema validation of tool-call args before invoke
37+
- Cross-hub federation loop prevention via `X-Zhub-Forwarded-By` / register-connection `via` chain
38+
- CORS allow-all is intentional on chat endpoints (auth is via Bearer, not origin)
39+
- Manifests carry no secrets — public discovery surface is safe to share
40+
41+
## Known operational caveats
42+
43+
- The hub's metrics counters and entity extensions are stored in plain SQLite; back them up like any small file. They contain no secrets but operators may treat the hub_id as semi-private.
44+
- The dashboard at `/` and `/api/dashboard` are public by default — they reveal publisher names, exposure capability names, and recent request paths. Run on an internal interface or behind a separate auth proxy if that's not acceptable.

pyproject.toml

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,25 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "zhub"
7-
version = "0.1.0"
8-
description = "WiFi for AIs — drop-in skill that lets any AI publish a discoverable, controllable endpoint."
7+
version = "0.2.0"
8+
description = "WiFi for AIs — substrate that lets any AI publish a discoverable, OpenAI-compat endpoint reachable from anywhere."
99
readme = "README.md"
1010
requires-python = ">=3.10"
1111
license = { text = "MIT" }
1212
authors = [{ name = "Zawwar Sami", email = "zawwarsami16@gmail.com" }]
13-
keywords = ["ai", "agent", "endpoint", "tunnel", "openai-compatible", "mcp"]
13+
keywords = ["ai", "agent", "endpoint", "tunnel", "openai-compatible", "mcp", "llm", "claude", "ollama", "groq"]
1414
classifiers = [
15-
"Development Status :: 3 - Alpha",
15+
"Development Status :: 4 - Beta",
1616
"License :: OSI Approved :: MIT License",
1717
"Programming Language :: Python :: 3.10",
1818
"Programming Language :: Python :: 3.11",
1919
"Programming Language :: Python :: 3.12",
20+
"Programming Language :: Python :: 3.13",
2021
"Topic :: Software Development :: Libraries",
22+
"Topic :: Internet :: WWW/HTTP :: HTTP Servers",
23+
"Topic :: Communications :: Chat",
24+
"Framework :: AsyncIO",
25+
"Operating System :: OS Independent",
2126
]
2227

2328
dependencies = [
@@ -49,6 +54,7 @@ Repository = "https://github.com/Zawwarsami16/zhub"
4954
Issues = "https://github.com/Zawwarsami16/zhub/issues"
5055

5156
[project.scripts]
57+
zhub = "zhub.__main__:main"
5258
zhub-server = "zhub.server:main"
5359

5460
[tool.hatch.build.targets.wheel]

zhub/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
except SystemExit:
5757
_SIGNING_AVAILABLE = False
5858

59-
__version__ = "0.1.0"
59+
__version__ = "0.2.0"
6060
__all__ = [
6161
"publish",
6262
"connect",

0 commit comments

Comments
 (0)