zing-cli 0.0.2

CLI tool + MCP server for paid semantic search on Zing
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
# zing-cli

CLI tool + MCP server for paid semantic search and chunk retrieval on the [Zing](https://github.com/ZingHall/zing-aggregator) decentralized knowledge platform. Executes USDC micro-payments on Sui and queries the `zing-indexbind` API.

Two usage personas:

- **CLI user** — run `zing search`, `zing chunks`, `zing expand` directly in a terminal
- **MCP agent** — AI agents use `zing mcp serve` to get `zing_search`, `zing_chunks`, `zing_expand_chunks` tools over stdio

---

## Prerequisites

1. **Rust toolchain** — edition 2021
2. **USDC on Sui** — at least 0.01 USDC on Sui mainnet to fund your zing wallet

---

## Installation

### Option 1: Install from GitHub

```bash
cargo install --git https://github.com/ZingHall/zing-cli.git zing-cli
```

### Option 2: Clone and build

```bash
git clone https://github.com/ZingHall/zing-cli.git
cd zing-cli
cargo install --path . --bin zing
```

### Option 3: Build in place

```bash
cargo build --release -p zing-cli
./target/release/zing version
```

The binary `zing` is placed in `~/.cargo/bin/` — ensure it's on your `PATH`.

### Verify

```bash
zing version
# → zing 0.1.0
```

---

## Configuration

Zing manages its own config and keypair, fully independent from Sui CLI.

### First run

On first run, zing auto-creates its config directory:

```
~/.zing/
  zing_config/
    client.yaml       — active address, active env, RPC endpoints
    zing.keystore     — Ed25519 private key (Sui keystore format)
```

A new Ed25519 keypair is generated and the address is printed. Fund this address with at least 0.01 USDC on Sui mainnet to use paid search.

### Defaults and overrides

| Variable | Overrides | Default |
|----------|-----------|---------|
| `ZING_API_URL` | API base URL | `https://search.zing.services` |
| `ZING_PLATFORM_USDC_ADDRESS` | Payment recipient | hardcoded platform address |
| `--api` flag | API base URL | overrides env/fallback |
| `--rpc` flag | Sui fullnode URL | `https://fullnode.mainnet.sui.io:443` |

---

## CLI Commands

### `zing version`

Show the CLI version.

```bash
zing version
```

---

### `zing search` — Paid semantic search

Search across all indexed wikis.

```bash
# Basic search
zing search "what is blockchain"

# Scoped to a specific creator's wiki
zing search "Move language" --owner 0x1aa2c40369fa0fffb12fe6e1415b8aba52d15cc3cf59e001adc5d2687920fbd6

# Custom result count (default: 20, max: 50)
zing search "DeFi" --limit 30

# Override endpoints
zing search "zk proofs" --api https://staging.api.com --rpc https://fullnode.mainnet.sui.io:443

# JSON output
zing search "Sui gas" --json
```

| Flag | Type | Description |
|------|------|-------------|
| `--owner` | string | Filter to a specific creator's wiki |
| `--limit` | int | Max results (default: 20, max: 50) |
| `--api` | string | Override API base URL |
| `--rpc` | string | Override Sui fullnode URL |
| `--json` | bool | Output JSON for agent consumption |

---

### `zing chunks` — Paid chunk retrieval

Retrieve semantic chunks with per-chunk pricing. Returns precise raw text segments with metadata.

```bash
# Basic chunk retrieval
zing chunks "zero-knowledge proofs"

# Return full untruncated text (no excerpts)
zing chunks "consensus" --expand

# Scoped with custom limit
zing chunks "Move language" --owner 0xabc... --limit 30

# JSON output
zing chunks "smart contracts" --json
```

| Flag | Type | Description |
|------|------|-------------|
| `--owner` | string | Filter to a specific creator's wiki |
| `--limit` | int | Max results (default: 20, max: 50) |
| `--expand` | bool | Return full untruncated chunk text (no extra cost) |
| `--api` | string | Override API base URL |
| `--rpc` | string | Override Sui fullnode URL |
| `--json` | bool | Output JSON for agent consumption |

---

### `zing expand` — Expand truncated chunks

Retrieve the full untruncated text for up to 20 chunks by their IDs. Use this when a chunk result shows truncation metadata.

```bash
# Expand specific chunk IDs
zing expand 94 1603 1802

# JSON output
zing expand 94 1603 --json
```

| Flag | Type | Description |
|------|------|-------------|
| `--api` | string | Override API base URL |
| `--rpc` | string | Override Sui fullnode URL |
| `--json` | bool | Output JSON for agent consumption |

---

### `zing client` — Wallet utilities

```bash
# Show the active zing address
zing client active-address

# Show SUI and USDC balances
zing client balance
```

---

### `zing mcp serve` — Start MCP server

Start an MCP server on stdio for AI agent integration. Exposes `zing_search`, `zing_chunks`, and `zing_expand_chunks` as MCP tools. See [MCP Server](#mcp-server) for full documentation.

```bash
zing mcp serve

# With API override
zing mcp serve --api https://staging.api.com
```

| Flag | Type | Description |
|------|------|-------------|
| `--api` | string | Override API base URL |

---

## JSON Output Schemas

The `--json` flag on `search`, `chunks`, and `expand` commands returns structured JSON instead of human-readable output. All monetary values are in micro-USDC (1 USDC = 1,000,000 micro-USDC).

### Search (`--json`)

```json
{
  "results": [
    {
      "article_id": "0xf6bd...",
      "title": "Gas Fees",
      "excerpt": "When you submit transactions...",
      "heading_path": ["Introduction", "Gas Fees"],
      "score": 0.81,
      "article_token_count": 4200,
      "recency_days": 0,
      "tags": ["cryptocurrency", "defi"]
    }
  ],
  "budget": {
    "paid_usdc": "10000",
    "consumed_usdc": "1250",
    "remaining_usdc": "8750"
  }
}
```

### Chunks (`--json`)

```json
{
  "chunks": [
    {
      "chunk_id": 94,
      "article_id": "0xf6bd...",
      "title": "What is Web3",
      "text": "Web3 is the next generation of the internet...",
      "score": 2.14,
      "chunk_token_count": 116,
      "heading_path": ["Introduction"],
      "content_type": "prose",
      "language": null,
      "truncated": {
        "content_type": "prose",
        "prose_chars_total": 850,
        "prose_chars_shown": 280
      }
    }
  ],
  "budget": {
    "paid_usdc": "10000",
    "consumed_usdc": "797",
    "remaining_usdc": "9203"
  }
}
```

**Truncation:** When `truncated` is non-null, the `text` field is an excerpt. The `truncated` object tells you what was omitted:

| Field | When | Meaning |
|-------|------|---------|
| `content_type` | always | `"prose"`, `"code"`, or `"table"` |
| `table_rows_total / table_rows_shown` | table chunks | Hidden data rows |
| `code_lines_total / code_lines_shown` | code chunks | Truncated lines |
| `prose_chars_total / prose_chars_shown` | prose chunks | Truncated characters |

Use `zing expand <chunk_id>` or the `zing_expand_chunks` MCP tool to retrieve the full text.

### Expand (`--json`)

```json
{
  "chunks": [
    {
      "chunk_id": 94,
      "article_id": "0xf6bd...",
      "heading_path": ["Introduction", "What is Web3"],
      "chunk_text": "Web3 is the next generation of the internet...\n\n(full untruncated text)",
      "content_type": "prose",
      "token_count": 116,
      "truncated": {
        "content_type": "table",
        "table_rows_total": 15,
        "table_rows_shown": 3
      }
    }
  ],
  "budget": {
    "paid_usdc": "10000",
    "consumed_usdc": "2320",
    "remaining_usdc": "7680"
  }
}
```

---

## MCP Server

`zing mcp serve` starts an MCP server over stdio that AI agents (Claude Desktop, Cursor, Codex, etc.) can connect to as a subprocess. The server provides three tools.

### Client Setup

**Claude Desktop** — add to `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "zing": {
      "command": "zing",
      "args": ["mcp", "serve"]
    }
  }
}
```

**Cursor** — add to `.cursor/mcp.json`:

```json
{
  "mcpServers": {
    "zing": {
      "command": "zing",
      "args": ["mcp", "serve"]
    }
  }
}
```

**With API override:**

```json
{
  "command": "zing",
  "args": ["mcp", "serve", "--api", "https://staging.api.com"]
}
```

---

### Tool: `zing_search`

**Description:**

> Search the Zing decentralized knowledge base. Provide short keyword queries (2-4 words preferred). Returns articles with relevance scores, excerpts, tags, and budget info. Default limit is 20.

**Parameters:**

| Param | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `q` | string | yes || Search query (compact keywords preferred) |
| `owner` | string | no | `null` | Filter to specific creator's wiki address |
| `limit` | int | no | `20` | Max results (capped at 50) |

**Response fields:**

| Field | Type | Description |
|-------|------|-------------|
| `results[].article_id` | string | On-chain article address |
| `results[].title` | string | Article title |
| `results[].excerpt` | string or null | Best-matching text snippet |
| `results[].heading_path` | string[] | Heading hierarchy for the match |
| `results[].score` | float | Relevance score (cross-encoder reranked) |
| `results[].article_token_count` | int | Total tokens in the article |
| `results[].recency_days` | int | Days since last index |
| `results[].tags` | string[] | Extracted topic tags |
| `budget.paid_usdc` | string | Total USDC sent (in micro-USDC) |
| `budget.consumed_usdc` | string | USDC consumed by this request |
| `budget.remaining_usdc` | string | USDC remaining after this request |

---

### Tool: `zing_chunks`

**Description:**

> Retrieve raw text segments from search results with per-chunk pricing. Provide short keyword queries. Returns chunks with text, scores, content_type, and truncation metadata. Set expand=true (no extra cost) to return full text instead of excerpts. Use article_ids to filter to specific articles. When truncation metadata is present, call zing_expand_chunks with those chunk_ids to retrieve full text. Default limit is 20.

**Parameters:**

| Param | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `q` | string | yes || Search query (compact 2-4 word keywords) |
| `owner` | string | no | `null` | Filter to specific creator's wiki address |
| `limit` | int | no | `20` | Max results (capped at 50) |
| `expand` | bool | no | `false` | Return full untruncated text instead of excerpts (no extra cost) |
| `article_ids` | string[] | no | `null` | Filter to specific article IDs |

**Response fields:**

| Field | Type | Description |
|-------|------|-------------|
| `chunks[].chunk_id` | int | Unique chunk identifier |
| `chunks[].article_id` | string | On-chain article address |
| `chunks[].title` | string | Article title |
| `chunks[].text` | string | Chunk text (excerpt or full if `expand=true`) |
| `chunks[].score` | float | Blended relevance score |
| `chunks[].chunk_token_count` | int | Estimated tokens in this chunk |
| `chunks[].heading_path` | string[] | Heading hierarchy |
| `chunks[].content_type` | string | `"prose"`, `"code"`, or `"table"` |
| `chunks[].language` | string or null | Programming language for code chunks |
| `chunks[].truncated` | object or null | Truncation metadata (see below) |
| `budget.*` | string | Same structure as `zing_search` |

**Truncation workflow:**

```
zing_chunks → chunk.truncated is non-null → zing_expand_chunks(chunk_ids) → full text
```

---

### Tool: `zing_expand_chunks`

**Description:**

> Expand truncated chunks to retrieve full untruncated text. Pass chunk_ids from chunks results that have non-null truncated fields. Max 20 chunk IDs per call.

**Parameters:**

| Param | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `chunk_ids` | int[] | yes || Chunk IDs to expand (max 20) |

**Response fields:**

| Field | Type | Description |
|-------|------|-------------|
| `chunks[].chunk_id` | int | Chunk identifier |
| `chunks[].article_id` | string | On-chain article address |
| `chunks[].heading_path` | string[] | Heading hierarchy |
| `chunks[].chunk_text` | string | Full untruncated chunk content |
| `chunks[].content_type` | string | `"prose"`, `"code"`, or `"table"` |
| `chunks[].token_count` | int | Estimated tokens |
| `chunks[].truncated` | object or null | Truncation metadata (always non-null for expand) |
| `budget.*` | string | Same structure as `zing_search` |

---

## Payment Flow

Each request costs a flat search/infrastructure fee (default 0.0005 USDC for ≤20 results, scales linearly for larger limits) plus per-result/per-chunk token fees:

1. **Send USDC** — the CLI sends USDC via `0x2::balance::send_funds<USDC>` to the platform address. USDC coins are always consolidated into address balance before payment to avoid stale RPC cache issues.
2. **Sign message** — BCS-encodes `ApiAccessMessage {q, wiki, transaction_digest, timestamp, expand?, article_ids?}` and signs as a `PersonalMessage` with the Ed25519 keypair from `zing.keystore`.
3. **Submit** — sends the signed request to the indexbind API. The server verifies the on-chain payment, runs the search/chunk pipeline, and returns results up to the paid budget.

The budget breakdown is shown in all output:

```
Budget: paid=10000, consumed=1250, remaining=8750
```

---

## Project Structure

```
zing-cli/
  Cargo.toml        — workspace root (zing-cli + zing-eval)
  README.md
  src/
    main.rs         — CLI entry: clap subcommands, output formatting
    lib.rs          — module declarations
    config.rs       — loads config, auto-creates keypair on first run
    error.rs        — typed error codes
    keystore.rs     — loads Ed25519 keypair from zing.keystore
    sui.rs          — USDC balance, coin consolidation, payment PTB
    api.rs          — ApiAccessMessage signing + HTTP calls
    models.rs       — request/response types (serde)
    mcp.rs          — MCP server (zing_search, zing_chunks, zing_expand_chunks tools)
  eval/             — zing-eval RAG evaluation framework
    src/
      main.rs       — eval CLI (run, list, formula)
      checks.rs     — L1 retrieval / L2 score sanity
      golden.rs     — YAML query loader
      runner.rs     — API client for chunk/search estimate
      l3_eval.rs    — LLM judge (opt-in)
      report.rs     — JSON report writer
      types.rs      — shared types
    queries/        — golden query YAML definitions
```