|
| 1 | +--- |
| 2 | +name: knowledge-admin |
| 3 | +description: "Administrative operations on the Knowledge base: connect new pgvector servers, check health, view stats, export data, install parser models. Use when the user wants to configure/monitor the system ('connect a new pgvector', 'status of connections', 'how many docs do we have', 'export backup of space X', 'install Marker models')." |
| 4 | +--- |
| 5 | + |
| 6 | +# knowledge-admin |
| 7 | + |
| 8 | +Group: **Administration**. Consolidates connect/health/stats/export/install-parser via subcommand. |
| 9 | + |
| 10 | +## When to trigger |
| 11 | + |
| 12 | +- "Connect a new pgvector" |
| 13 | +- "Status of connections" |
| 14 | +- "How many docs are in Academy?" |
| 15 | +- "Export space X as backup" |
| 16 | +- "Install Marker models" |
| 17 | + |
| 18 | +## Arguments |
| 19 | + |
| 20 | +| Name | Type | Required | Description | |
| 21 | +|---|---|---|---| |
| 22 | +| `action` | str | yes | `connect` \| `health` \| `stats` \| `export` \| `install-parser` | |
| 23 | +| (action-specific args) | | | see below | |
| 24 | + |
| 25 | +## Actions |
| 26 | + |
| 27 | +### `connect` — New connection wizard |
| 28 | + |
| 29 | +Optional args: `slug`, `name`, `host`, `port`, `database`, `username`, `password`, `ssl_mode`, `connection_string`. |
| 30 | + |
| 31 | +Flow: |
| 32 | + |
| 33 | +1. If args missing, ask interactively (chat): |
| 34 | + - Name ("What do you want to call this connection?") |
| 35 | + - Host, port (default 5432), user, password, database, SSL mode |
| 36 | + - OR paste a full connection string |
| 37 | +2. `POST /api/knowledge/connections` — register (encryption via workspace key) |
| 38 | +3. `POST /api/knowledge/connections/:id/configure` — runs: |
| 39 | + - `SELECT version()` (Postgres >= 14) |
| 40 | + - Validate `pgvector` >= 0.5 |
| 41 | + - PgBouncer detect (port 6543, pooler, ?pgbouncer=true) → HTTP 422 with message |
| 42 | + - Alembic upgrade head |
| 43 | + - Seed `knowledge_config` |
| 44 | +4. Show phase-by-phase progress |
| 45 | +5. Output: final status + next steps ("create your first space via UI or `knowledge-organize action=create`") |
| 46 | + |
| 47 | +### `health` |
| 48 | + |
| 49 | +```python |
| 50 | +from dashboard.backend.sdk_client import evo |
| 51 | + |
| 52 | +conns = evo.get("/api/knowledge/connections") |
| 53 | +for c in conns: |
| 54 | + health = evo.get(f"/api/knowledge/connections/{c['id']}/health") |
| 55 | + # aggregate: status, schema_version, pgvector_version, chunks, spaces, last_error |
| 56 | +``` |
| 57 | + |
| 58 | +Output: |
| 59 | + |
| 60 | +``` |
| 61 | +| Connection | Status | Schema | pgvector | Spaces | Chunks | Last health | |
| 62 | +|---|---|---|---|---|---|---| |
| 63 | +| academy | ✅ ready | v3 | 0.5.1 | 5 | 12,400 | 2026-04-20 14:05 | |
| 64 | +| acme | ⚠️ needs_mig | v2 | 0.5.0 | 2 | 3,100 | 2026-04-20 14:05 | |
| 65 | +| staging | ❌ error | — | — | — | — | `connection refused` | |
| 66 | +``` |
| 67 | + |
| 68 | +### `stats` |
| 69 | + |
| 70 | +Aggregates per-connection + global stats: |
| 71 | + |
| 72 | +```python |
| 73 | +stats = evo.get("/api/knowledge/stats") |
| 74 | +# { connections: [...], total_documents: N, total_chunks: M, by_content_type: {...}, growth_7d: X } |
| 75 | +``` |
| 76 | + |
| 77 | +Output: |
| 78 | + |
| 79 | +``` |
| 80 | +## Knowledge stats |
| 81 | +
|
| 82 | +Total documents: {N} |
| 83 | +Total chunks: {M} |
| 84 | +Total spaces: {S} |
| 85 | +Growth (last 7d): +{X} docs, +{Y} chunks |
| 86 | +
|
| 87 | +### By content_type |
| 88 | +- lesson: {N} |
| 89 | +- tutorial: {N} |
| 90 | +- faq: {N} |
| 91 | +... |
| 92 | +
|
| 93 | +### Per connection |
| 94 | +| Connection | Docs | Chunks | Spaces | |
| 95 | +... |
| 96 | +``` |
| 97 | + |
| 98 | +### `export` |
| 99 | + |
| 100 | +Args: `space_id` (yes), `format` (default "jsonl"), `connection`. |
| 101 | + |
| 102 | +```python |
| 103 | +docs = evo.get( |
| 104 | + "/api/knowledge/v1/documents", |
| 105 | + params={"space_id": space_id, "format": "jsonl", "include_chunks": True}, |
| 106 | + headers={"X-Knowledge-Connection": connection}, |
| 107 | +) |
| 108 | + |
| 109 | +# Save to workspace/data/knowledge-exports/{connection}_{space_slug}_{timestamp}.jsonl |
| 110 | +from pathlib import Path |
| 111 | +import json |
| 112 | +from datetime import datetime |
| 113 | + |
| 114 | +out = Path("workspace/data/knowledge-exports") / \ |
| 115 | + f"{connection}_{space_id}_{datetime.now():%Y%m%d_%H%M%S}.jsonl" |
| 116 | +out.parent.mkdir(parents=True, exist_ok=True) |
| 117 | +with out.open("w") as f: |
| 118 | + for doc in docs: |
| 119 | + f.write(json.dumps(doc, ensure_ascii=False) + "\n") |
| 120 | + |
| 121 | +print(f"Exported {len(docs)} docs to {out}") |
| 122 | +``` |
| 123 | + |
| 124 | +### `install-parser` |
| 125 | + |
| 126 | +Downloads Marker models (Surya OCR ~500MB). Idempotent — uses sentinel file. |
| 127 | + |
| 128 | +```python |
| 129 | +resp = evo.post("/api/knowledge/parsers/install", {}) |
| 130 | +# poll /api/knowledge/parsers/status until installed=true |
| 131 | +``` |
| 132 | + |
| 133 | +Show progress. If already installed, no-op. |
| 134 | + |
| 135 | +## Actionable failures |
| 136 | + |
| 137 | +- Invalid `action` → list actions |
| 138 | +- Invalid credentials on connect → "Check host/port/user" |
| 139 | +- PgBouncer detected → exact message from ADR-009 |
| 140 | +- Export without write permission → "Create `workspace/data/knowledge-exports/` manually" |
| 141 | +- Install-parser without disk → "No space. Marker needs ~500MB." |
0 commit comments