@gobi-ai/cli 1.0.0 → 1.1.0
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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +3 -3
- package/dist/commands/init.js +5 -5
- package/dist/commands/vault.js +9 -11
- package/package.json +1 -1
- package/skills/gobi-core/SKILL.md +3 -3
- package/skills/gobi-homepage/SKILL.md +19 -125
- package/skills/gobi-vault/SKILL.md +14 -14
- package/skills/gobi-vault/references/vault.md +5 -5
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
"name": "gobi-ai"
|
|
5
5
|
},
|
|
6
6
|
"description": "Claude Code plugin for the Gobi collaborative knowledge platform CLI",
|
|
7
|
-
"version": "1.
|
|
7
|
+
"version": "1.1.0",
|
|
8
8
|
"plugins": [
|
|
9
9
|
{
|
|
10
10
|
"name": "gobi",
|
|
11
11
|
"description": "Manage the Gobi collaborative knowledge platform from the command line. Search and ask vaults, publish vault documents, create threads, manage sessions, generate images and videos.",
|
|
12
|
-
"version": "1.
|
|
12
|
+
"version": "1.1.0",
|
|
13
13
|
"author": {
|
|
14
14
|
"name": "gobi-ai"
|
|
15
15
|
},
|
package/README.md
CHANGED
|
@@ -71,8 +71,8 @@ gobi vault ask --vault-slug my-vault --question "What is RAG?"
|
|
|
71
71
|
|---------|-------------|
|
|
72
72
|
| `gobi vault search --query <q>` | Search public vaults by text and semantic similarity |
|
|
73
73
|
| `gobi vault ask --vault-slug <slug> --question <q>` | Ask a vault a question (creates a 1:1 session) |
|
|
74
|
-
| `gobi vault publish` | Upload `
|
|
75
|
-
| `gobi vault unpublish` | Remove `
|
|
74
|
+
| `gobi vault publish` | Upload `PUBLISH.md` to your vault |
|
|
75
|
+
| `gobi vault unpublish` | Remove `PUBLISH.md` from your vault |
|
|
76
76
|
|
|
77
77
|
Public vaults are accessible at `https://gobispace.com/@{vaultSlug}`.
|
|
78
78
|
|
|
@@ -90,7 +90,7 @@ Public vaults are accessible at `https://gobispace.com/@{vaultSlug}`.
|
|
|
90
90
|
|
|
91
91
|
### Threads
|
|
92
92
|
|
|
93
|
-
> **Migration note:**
|
|
93
|
+
> **Migration note:** Vault-update (formerly brain-update) commands have been removed. To post user-level content, use `gobi global create-thread` (platform-wide global) or `gobi space create-thread` (a specific space).
|
|
94
94
|
|
|
95
95
|
| Command | Description |
|
|
96
96
|
|---------|-------------|
|
package/dist/commands/init.js
CHANGED
|
@@ -205,11 +205,11 @@ export async function runInitFlow() {
|
|
|
205
205
|
writeVaultSetting(vaultId);
|
|
206
206
|
console.log(`Vault set to "${vaultName}" (${vaultId})`);
|
|
207
207
|
console.log(`Updated ${SETTINGS_DIR}/${SETTINGS_FILE}`);
|
|
208
|
-
// Create default
|
|
209
|
-
const
|
|
210
|
-
if (!existsSync(
|
|
211
|
-
writeFileSync(
|
|
212
|
-
console.log("Created
|
|
208
|
+
// Create default PUBLISH.md if it doesn't exist
|
|
209
|
+
const publishMdPath = join(process.cwd(), "PUBLISH.md");
|
|
210
|
+
if (!existsSync(publishMdPath)) {
|
|
211
|
+
writeFileSync(publishMdPath, `---\ntitle: ${vaultName}\ntags: []\ndescription:\nthumbnail:\nprompt:\n---\n`, "utf-8");
|
|
212
|
+
console.log("Created PUBLISH.md");
|
|
213
213
|
}
|
|
214
214
|
}
|
|
215
215
|
export function registerInitCommand(program) {
|
package/dist/commands/vault.js
CHANGED
|
@@ -8,7 +8,7 @@ import { isJsonMode, jsonOut, unwrapResp } from "./utils.js";
|
|
|
8
8
|
export function registerVaultCommand(program) {
|
|
9
9
|
const vaultCmd = program
|
|
10
10
|
.command("vault")
|
|
11
|
-
.description("Vault commands. A Vault is your personal knowledge container — search public vaults, ask them questions, and publish
|
|
11
|
+
.description("Vault commands. A Vault is your personal knowledge container — search public vaults, ask them questions, and publish a PUBLISH.md to make a vault public.");
|
|
12
12
|
// ── Search ──
|
|
13
13
|
vaultCmd
|
|
14
14
|
.command("search")
|
|
@@ -88,20 +88,18 @@ export function registerVaultCommand(program) {
|
|
|
88
88
|
` Question sent.`);
|
|
89
89
|
});
|
|
90
90
|
// ── Publish ──
|
|
91
|
-
// Note: file is still named BRAIN.md on webdrive — the post-processing pipeline
|
|
92
|
-
// (gobi-webdrive) hardcodes the filename. Rename the file here once that ships.
|
|
93
91
|
vaultCmd
|
|
94
92
|
.command("publish")
|
|
95
|
-
.description("Upload
|
|
93
|
+
.description("Upload PUBLISH.md to the vault root on webdrive. Triggers post-processing (vault sync, metadata update, Discord notification).")
|
|
96
94
|
.action(async () => {
|
|
97
95
|
const vaultId = getVaultSlug();
|
|
98
|
-
const filePath = join(process.cwd(), "
|
|
96
|
+
const filePath = join(process.cwd(), "PUBLISH.md");
|
|
99
97
|
if (!existsSync(filePath)) {
|
|
100
|
-
throw new Error(`
|
|
98
|
+
throw new Error(`PUBLISH.md not found in ${process.cwd()}`);
|
|
101
99
|
}
|
|
102
100
|
const content = readFileSync(filePath, "utf-8");
|
|
103
101
|
const token = await getValidToken();
|
|
104
|
-
const url = `${WEBDRIVE_BASE_URL}/api/v1/vaults/${vaultId}/file/
|
|
102
|
+
const url = `${WEBDRIVE_BASE_URL}/api/v1/vaults/${vaultId}/file/PUBLISH.md`;
|
|
105
103
|
const res = await fetch(url, {
|
|
106
104
|
method: "PUT",
|
|
107
105
|
headers: {
|
|
@@ -117,16 +115,16 @@ export function registerVaultCommand(program) {
|
|
|
117
115
|
jsonOut({ vaultId });
|
|
118
116
|
return;
|
|
119
117
|
}
|
|
120
|
-
console.log(`Published
|
|
118
|
+
console.log(`Published PUBLISH.md to vault "${vaultId}"`);
|
|
121
119
|
});
|
|
122
120
|
// ── Unpublish ──
|
|
123
121
|
vaultCmd
|
|
124
122
|
.command("unpublish")
|
|
125
|
-
.description("Delete
|
|
123
|
+
.description("Delete PUBLISH.md from the vault on webdrive.")
|
|
126
124
|
.action(async () => {
|
|
127
125
|
const vaultId = getVaultSlug();
|
|
128
126
|
const token = await getValidToken();
|
|
129
|
-
const url = `${WEBDRIVE_BASE_URL}/api/v1/vaults/${vaultId}/file/
|
|
127
|
+
const url = `${WEBDRIVE_BASE_URL}/api/v1/vaults/${vaultId}/file/PUBLISH.md`;
|
|
130
128
|
const res = await fetch(url, {
|
|
131
129
|
method: "DELETE",
|
|
132
130
|
headers: { Authorization: `Bearer ${token}` },
|
|
@@ -138,6 +136,6 @@ export function registerVaultCommand(program) {
|
|
|
138
136
|
jsonOut({ vaultId });
|
|
139
137
|
return;
|
|
140
138
|
}
|
|
141
|
-
console.log(`Deleted
|
|
139
|
+
console.log(`Deleted PUBLISH.md from vault "${vaultId}"`);
|
|
142
140
|
});
|
|
143
141
|
}
|
package/package.json
CHANGED
|
@@ -39,7 +39,7 @@ brew tap gobi-ai/tap && brew install gobi
|
|
|
39
39
|
## Key Concepts
|
|
40
40
|
|
|
41
41
|
- **Space**: A shared space for a group or community. A logged-in user can be a member of one or more spaces. A space contains threads, sessions, and connected vaults.
|
|
42
|
-
- **Vault**: A personal knowledge container — a filetree storage of information and knowledge that can also be searched and asked questions like a knowledge base. A local directory becomes a vault when it contains `.gobi/settings.yaml` with a vault slug and a space slug. Each vault is identified by a slug (e.g. `brave-path-zr962w`). Publish a `
|
|
42
|
+
- **Vault**: A personal knowledge container — a filetree storage of information and knowledge that can also be searched and asked questions like a knowledge base. A local directory becomes a vault when it contains `.gobi/settings.yaml` with a vault slug and a space slug. Each vault is identified by a slug (e.g. `brave-path-zr962w`). Publish a `PUBLISH.md` document at the vault root to configure the vault's public profile and AI agent.
|
|
43
43
|
|
|
44
44
|
## First-Time Setup
|
|
45
45
|
|
|
@@ -55,7 +55,7 @@ This is an **interactive** command that:
|
|
|
55
55
|
1. Logs in automatically if not already authenticated (opens a browser URL for Google OAuth)
|
|
56
56
|
2. Prompts the user to select an existing vault or create a new one
|
|
57
57
|
3. Writes `.gobi/settings.yaml` in the current directory with the chosen vault slug
|
|
58
|
-
4. Creates a `
|
|
58
|
+
4. Creates a `PUBLISH.md` file if one doesn't exist
|
|
59
59
|
|
|
60
60
|
### Step 2: Select a Space
|
|
61
61
|
|
|
@@ -127,7 +127,7 @@ JSON responses have the shape `{ "success": true, "data": ... }` on success or `
|
|
|
127
127
|
|------|-------------|
|
|
128
128
|
| `~/.gobi/credentials.json` | Stored authentication tokens (auto-managed) |
|
|
129
129
|
| `.gobi/settings.yaml` | Per-project vault and space configuration |
|
|
130
|
-
| `
|
|
130
|
+
| `PUBLISH.md` | Vault profile document with YAML frontmatter, published via `gobi vault publish` |
|
|
131
131
|
|
|
132
132
|
## Environment Variables
|
|
133
133
|
|
|
@@ -8,7 +8,7 @@ description: >-
|
|
|
8
8
|
|
|
9
9
|
# Gobi Homepage Developer Guide
|
|
10
10
|
|
|
11
|
-
A **Gobi Homepage** is a custom HTML page hosted on a vault's webdrive and served as its public homepage at `https://gobispace.com/@{vaultSlug}`. Gobi injects a `window.gobi` bridge before any scripts run, giving the homepage access to vault data, files,
|
|
11
|
+
A **Gobi Homepage** is a custom HTML page hosted on a vault's webdrive and served as its public homepage at `https://gobispace.com/@{vaultSlug}`. Gobi injects a `window.gobi` bridge before any scripts run, giving the homepage access to vault data, files, and chat.
|
|
12
12
|
|
|
13
13
|
> **Sandbox:** The homepage runs in a sandboxed iframe with `origin: null`. Direct `fetch()` / `XMLHttpRequest` calls are blocked by CORS. All data access must go through `window.gobi.*`.
|
|
14
14
|
|
|
@@ -20,7 +20,7 @@ A **Gobi Homepage** is a custom HTML page hosted on a vault's webdrive and serve
|
|
|
20
20
|
```bash
|
|
21
21
|
gobi sync
|
|
22
22
|
```
|
|
23
|
-
2. Set `homepage` in
|
|
23
|
+
2. Set `homepage` in PUBLISH.md (homepage property):
|
|
24
24
|
- `homepage: "[[app/home.html]]"` — Gobi sidebars visible alongside the homepage
|
|
25
25
|
- `homepage: "[[app/home.html?nav=false]]"` — full-screen, no Gobi chrome
|
|
26
26
|
|
|
@@ -67,31 +67,6 @@ function getFileUrl(path) {
|
|
|
67
67
|
}
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
### Brain Updates
|
|
71
|
-
|
|
72
|
-
```js
|
|
73
|
-
const { data: updates, pagination } = await gobi.listBrainUpdates({ limit: 10, cursor: null });
|
|
74
|
-
// updates[i] → {
|
|
75
|
-
// id: 42,
|
|
76
|
-
// title: 'New insights',
|
|
77
|
-
// content: '## ...', // markdown — MAY contain ![[file|width]] wiki image embeds
|
|
78
|
-
// topics: [{ id: 3, name: 'AI', slug: 'ai' }],
|
|
79
|
-
// createdAt: '2025-03-01T12:00:00Z'
|
|
80
|
-
// }
|
|
81
|
-
// pagination → { hasMore: true, nextCursor: 'abc...' }
|
|
82
|
-
|
|
83
|
-
// ⚠️ Always call resolveWikiImages() on content before rendering — see Rendering Markdown below.
|
|
84
|
-
for (const u of updates) {
|
|
85
|
-
el.innerHTML += marked.parse(resolveWikiImages(u.content));
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Pagination — load the next page using the cursor
|
|
89
|
-
if (pagination.hasMore) {
|
|
90
|
-
const { data: moreUpdates, pagination: nextPage } =
|
|
91
|
-
await gobi.listBrainUpdates({ limit: 10, cursor: pagination.nextCursor });
|
|
92
|
-
}
|
|
93
|
-
```
|
|
94
|
-
|
|
95
70
|
### Chat (login required)
|
|
96
71
|
|
|
97
72
|
`getSessions`, `loadMessages`, and `sendMessage` require the visitor to be logged in. `getSessions` returns an empty array when not logged in — **but also when logged in with no prior sessions**. Don't use it as a definitive auth check.
|
|
@@ -119,7 +94,7 @@ const { messages, hasMore, nextCursor } = await gobi.loadMessages('sess_abc', {
|
|
|
119
94
|
// sendMessage(sessionId, text, options, onDelta) → Promise<{ content }>
|
|
120
95
|
//
|
|
121
96
|
// options.context tells the AI what the user is looking at:
|
|
122
|
-
// {
|
|
97
|
+
// { filePath?: string }
|
|
123
98
|
|
|
124
99
|
let reply = '';
|
|
125
100
|
await gobi.sendMessage(sessionId, 'Hello', (delta) => {
|
|
@@ -128,10 +103,6 @@ await gobi.sendMessage(sessionId, 'Hello', (delta) => {
|
|
|
128
103
|
});
|
|
129
104
|
|
|
130
105
|
// With context
|
|
131
|
-
await gobi.sendMessage(sessionId, 'Tell me more', {
|
|
132
|
-
context: { brainUpdateId: 42, brainUpdateTitle: 'New insights' }
|
|
133
|
-
}, (delta) => { reply += delta; renderReply(reply); });
|
|
134
|
-
|
|
135
106
|
await gobi.sendMessage(sessionId, 'Explain this', {
|
|
136
107
|
context: { filePath: 'notes/research.md' }
|
|
137
108
|
}, (delta) => { reply += delta; renderReply(reply); });
|
|
@@ -144,7 +115,7 @@ sessionId = crypto.randomUUID();
|
|
|
144
115
|
|
|
145
116
|
## Rendering Markdown
|
|
146
117
|
|
|
147
|
-
|
|
118
|
+
Markdown read via `readFile` may contain Obsidian-style wiki embeds (`![[path|width]]`). Resolve them before passing to a renderer.
|
|
148
119
|
|
|
149
120
|
The examples below use [marked](https://cdn.jsdelivr.net/npm/marked/marked.min.js) — include it in your `<head>`:
|
|
150
121
|
|
|
@@ -162,7 +133,7 @@ function resolveWikiImages(md) {
|
|
|
162
133
|
});
|
|
163
134
|
}
|
|
164
135
|
|
|
165
|
-
const html = marked.parse(resolveWikiImages(
|
|
136
|
+
const html = marked.parse(resolveWikiImages(text));
|
|
166
137
|
```
|
|
167
138
|
|
|
168
139
|
**Open links in a new tab.** The homepage runs in a sandboxed iframe — clicking a rendered link replaces the iframe with the external page. Override the renderer so every `<a>` opens in a new tab:
|
|
@@ -175,7 +146,7 @@ renderer.link = (href, title, text) =>
|
|
|
175
146
|
marked.setOptions({ renderer });
|
|
176
147
|
```
|
|
177
148
|
|
|
178
|
-
**Plain-text previews.** For
|
|
149
|
+
**Plain-text previews.** For preview cards, render a truncated preview with `escapeHtml(content.substring(0, 200))` — don't run markdown on a random substring, it produces broken HTML. Use `marked.parse(resolveWikiImages(content))` only for the full expanded view. Same for chat: `marked.parse(content)` for assistant messages, `escapeHtml(content)` for human messages.
|
|
179
150
|
|
|
180
151
|
---
|
|
181
152
|
|
|
@@ -202,58 +173,9 @@ Centralize colors and spacing in CSS custom properties so restyling is a one-lin
|
|
|
202
173
|
|
|
203
174
|
Pair with Google Fonts (e.g. Space Grotesk for headings, IBM Plex Mono for meta, Inter for body) via CDN `<link>`.
|
|
204
175
|
|
|
205
|
-
### Knowledge Graph from BU topics
|
|
206
|
-
|
|
207
|
-
Brain updates carry a `topics` array. Treat each topic as a node and any two topics co-occurring in the same BU as an edge — you get a force-directed graph of the vault's themes for free. Use [d3](https://cdn.jsdelivr.net/npm/d3@7/dist/d3.min.js).
|
|
208
|
-
|
|
209
|
-
```js
|
|
210
|
-
// Separate data-building from rendering so the same graph can be drawn at multiple sizes.
|
|
211
|
-
function buildGraphData(updates) {
|
|
212
|
-
const counts = new Map(); // name → frequency
|
|
213
|
-
const edges = new Map(); // "a|b" → weight
|
|
214
|
-
for (const u of updates) {
|
|
215
|
-
const names = (u.topics || []).map(t => t.name);
|
|
216
|
-
for (const n of names) counts.set(n, (counts.get(n) || 0) + 1);
|
|
217
|
-
for (let i = 0; i < names.length; i++)
|
|
218
|
-
for (let j = i + 1; j < names.length; j++) {
|
|
219
|
-
const key = [names[i], names[j]].sort().join('|');
|
|
220
|
-
edges.set(key, (edges.get(key) || 0) + 1);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
// Top 20 by frequency, then drop orphans (nodes with no surviving edges).
|
|
224
|
-
const top = [...counts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 20).map(([n]) => n);
|
|
225
|
-
const keep = new Set(top);
|
|
226
|
-
const links = [...edges].flatMap(([k, w]) => {
|
|
227
|
-
const [a, b] = k.split('|');
|
|
228
|
-
return keep.has(a) && keep.has(b) ? [{ source: a, target: b, weight: w }] : [];
|
|
229
|
-
});
|
|
230
|
-
const connected = new Set(links.flatMap(l => [l.source, l.target]));
|
|
231
|
-
const nodes = top.filter(n => connected.has(n)).map(n => ({ id: n, count: counts.get(n) }));
|
|
232
|
-
return { nodes, links };
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
function drawGraph(containerId, w, h, data, opts = {}) {
|
|
236
|
-
const { nodeRange = [4, 16], fontSize = '9px', distance = 60, charge = -80 } = opts;
|
|
237
|
-
const max = Math.max(...data.nodes.map(n => n.count), 1);
|
|
238
|
-
const r = d3.scaleSqrt().domain([1, max]).range(nodeRange);
|
|
239
|
-
const svg = d3.select('#' + containerId).append('svg').attr('width', w).attr('height', h);
|
|
240
|
-
// ... standard d3.forceSimulation with link/charge/center, then clamp in tick:
|
|
241
|
-
// node.attr('cx', d => d.x = Math.max(20, Math.min(w - 20, d.x)))
|
|
242
|
-
// node.attr('cy', d => d.y = Math.max(20, Math.min(h - 20, d.y)))
|
|
243
|
-
// Node fill: accent with opacity 0.3 + 0.7 * (count/max).
|
|
244
|
-
// Call d3.drag() on nodes so visitors can rearrange the graph.
|
|
245
|
-
}
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
Tips:
|
|
249
|
-
- **Enrich the data.** One page of 8 BUs makes a sparse graph. Paginate 3–4 times (cap at ~32 BUs) before building.
|
|
250
|
-
- **Cache the built data** in a module-level variable so the full-screen overlay can reuse it without refetching.
|
|
251
|
-
- **Mini vs full presets.** Pass different `opts` — e.g. mini `{nodeRange:[4,16], fontSize:'9px', distance:60, charge:-80}`, full `{nodeRange:[8,32], fontSize:'12px', distance:120, charge:-200}`.
|
|
252
|
-
- Run a **separate simulation** for the full-scale instance — copy the nodes/links rather than sharing references, otherwise both graphs fight over the same positions.
|
|
253
|
-
|
|
254
176
|
### Full-screen overlay
|
|
255
177
|
|
|
256
|
-
Useful for expanding
|
|
178
|
+
Useful for expanding any small component into a focused view:
|
|
257
179
|
|
|
258
180
|
```js
|
|
259
181
|
function openOverlay(renderInto) {
|
|
@@ -272,27 +194,12 @@ function openOverlay(renderInto) {
|
|
|
272
194
|
|
|
273
195
|
Always restore `body.overflow` on close, and always remove the `keydown` listener.
|
|
274
196
|
|
|
275
|
-
### Brain update card — preview/full toggle
|
|
276
|
-
|
|
277
|
-
Show a truncated card that expands in place on click:
|
|
278
|
-
|
|
279
|
-
```js
|
|
280
|
-
card.onclick = (event) => {
|
|
281
|
-
// Link click guard — don't toggle when the user clicked a link inside the card.
|
|
282
|
-
if (event.target.closest('a')) return;
|
|
283
|
-
card.classList.toggle('expanded');
|
|
284
|
-
card.querySelector('.body').innerHTML = card.classList.contains('expanded')
|
|
285
|
-
? marked.parse(resolveWikiImages(update.content))
|
|
286
|
-
: escapeHtml(update.content.substring(0, 200));
|
|
287
|
-
};
|
|
288
|
-
```
|
|
289
|
-
|
|
290
197
|
### Chat suggestion chips
|
|
291
198
|
|
|
292
199
|
Empty chat looks dead. Show clickable prompt chips until the first message is sent:
|
|
293
200
|
|
|
294
201
|
```js
|
|
295
|
-
const prompts = ['What is this
|
|
202
|
+
const prompts = ['What is this vault about?', 'Summarize the latest notes', 'What topics come up most?'];
|
|
296
203
|
chips.innerHTML = prompts.map(p => `<button class="chip">${escapeHtml(p)}</button>`).join('');
|
|
297
204
|
chips.querySelectorAll('.chip').forEach((btn, i) => {
|
|
298
205
|
btn.onclick = () => { input.value = prompts[i]; chips.remove(); input.focus(); };
|
|
@@ -317,7 +224,7 @@ Single breakpoint at `768px` is enough for most homepages:
|
|
|
317
224
|
|
|
318
225
|
```css
|
|
319
226
|
@media (max-width: 768px) {
|
|
320
|
-
.hero-grid
|
|
227
|
+
.hero-grid { grid-template-columns: 1fr; }
|
|
321
228
|
.hero-content { flex-direction: column; }
|
|
322
229
|
.btn { width: 100%; }
|
|
323
230
|
}
|
|
@@ -336,9 +243,9 @@ Single breakpoint at `768px` is enough for most homepages:
|
|
|
336
243
|
<style>
|
|
337
244
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
338
245
|
body { font-family: system-ui, sans-serif; max-width: 720px; margin: 0 auto; padding: 24px; }
|
|
339
|
-
.
|
|
340
|
-
.
|
|
341
|
-
.
|
|
246
|
+
.hero { margin-bottom: 32px; }
|
|
247
|
+
.hero h1 { margin-bottom: 8px; }
|
|
248
|
+
.hero p { color: #555; }
|
|
342
249
|
#chat { margin-top: 40px; border-top: 1px solid #ddd; padding-top: 24px; }
|
|
343
250
|
.message { margin-bottom: 12px; padding: 8px 12px; border-radius: 8px; }
|
|
344
251
|
.message[data-role="human"] { background: #e8f0fe; }
|
|
@@ -351,7 +258,10 @@ Single breakpoint at `768px` is enough for most homepages:
|
|
|
351
258
|
</style>
|
|
352
259
|
</head>
|
|
353
260
|
<body>
|
|
354
|
-
<div
|
|
261
|
+
<div class="hero">
|
|
262
|
+
<h1 id="title"></h1>
|
|
263
|
+
<p id="description"></p>
|
|
264
|
+
</div>
|
|
355
265
|
<div id="chat">
|
|
356
266
|
<div id="messages"></div>
|
|
357
267
|
<div id="chat-input">
|
|
@@ -361,7 +271,9 @@ Single breakpoint at `768px` is enough for most homepages:
|
|
|
361
271
|
</div>
|
|
362
272
|
|
|
363
273
|
<script>
|
|
364
|
-
document.title = gobi.vault.title || '
|
|
274
|
+
document.title = gobi.vault.title || 'Vault';
|
|
275
|
+
document.getElementById('title').textContent = gobi.vault.title || '';
|
|
276
|
+
document.getElementById('description').textContent = gobi.vault.description || '';
|
|
365
277
|
|
|
366
278
|
// ── Helpers ──────────────────────────────────────
|
|
367
279
|
|
|
@@ -389,23 +301,6 @@ Single breakpoint at `768px` is enough for most homepages:
|
|
|
389
301
|
`https://gobispace.com/login?redirect_uri=${encodeURIComponent(window.location.href)}`;
|
|
390
302
|
}
|
|
391
303
|
|
|
392
|
-
// ── Brain updates ────────────────────────────────
|
|
393
|
-
|
|
394
|
-
async function loadUpdates() {
|
|
395
|
-
try {
|
|
396
|
-
const { data: updates } = await gobi.listBrainUpdates({ limit: 5 });
|
|
397
|
-
const el = document.getElementById('updates');
|
|
398
|
-
for (const u of updates) {
|
|
399
|
-
const div = document.createElement('div');
|
|
400
|
-
div.className = 'update';
|
|
401
|
-
div.innerHTML = `<h2>${escapeHtml(u.title)}</h2>${marked.parse(resolveWikiImages(u.content))}`;
|
|
402
|
-
el.appendChild(div);
|
|
403
|
-
}
|
|
404
|
-
} catch (err) {
|
|
405
|
-
console.error('Failed to load brain updates:', err);
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
|
|
409
304
|
// ── Chat ─────────────────────────────────────────
|
|
410
305
|
|
|
411
306
|
let sessionId = null;
|
|
@@ -466,7 +361,6 @@ Single breakpoint at `768px` is enough for most homepages:
|
|
|
466
361
|
|
|
467
362
|
// ─────────────────────────────────────────────────
|
|
468
363
|
|
|
469
|
-
loadUpdates();
|
|
470
364
|
initChat();
|
|
471
365
|
</script>
|
|
472
366
|
</body>
|
|
@@ -3,23 +3,23 @@ name: gobi-vault
|
|
|
3
3
|
description: >-
|
|
4
4
|
Gobi vault commands for knowledge management: search public vaults by text
|
|
5
5
|
and semantic similarity, ask vaults questions, and publish/unpublish
|
|
6
|
-
|
|
6
|
+
PUBLISH.md. Use when the user wants to search knowledge, ask a vault, or
|
|
7
7
|
publish their vault document.
|
|
8
8
|
allowed-tools: Bash(gobi:*)
|
|
9
9
|
metadata:
|
|
10
10
|
author: gobi-ai
|
|
11
|
-
version: "1.
|
|
11
|
+
version: "1.1.0"
|
|
12
12
|
---
|
|
13
13
|
|
|
14
14
|
# gobi-vault
|
|
15
15
|
|
|
16
|
-
Gobi vault commands for knowledge management (v1.
|
|
16
|
+
Gobi vault commands for knowledge management (v1.1.0).
|
|
17
17
|
|
|
18
18
|
Requires gobi-cli installed and authenticated. See gobi-core skill for setup.
|
|
19
19
|
|
|
20
20
|
## Gobi Vault — Knowledge Management
|
|
21
21
|
|
|
22
|
-
`gobi vault` commands manage your vault: search public vaults, ask them questions, and publish/unpublish your `
|
|
22
|
+
`gobi vault` commands manage your vault: search public vaults, ask them questions, and publish/unpublish your `PUBLISH.md`. Public vaults are accessible at `https://gobispace.com/@{vaultSlug}`.
|
|
23
23
|
|
|
24
24
|
> **Vault updates have moved to threads.** To post user-level content, use `gobi global create-thread` (platform-wide global) or `gobi space create-thread` (a specific space). See the **gobi-space** skill.
|
|
25
25
|
|
|
@@ -35,12 +35,12 @@ gobi --json vault search --query "machine learning"
|
|
|
35
35
|
|
|
36
36
|
- `gobi vault search` — Search public vaults by text and semantic similarity.
|
|
37
37
|
- `gobi vault ask` — Ask a vault a question. Creates a targeted session (1:1 conversation).
|
|
38
|
-
- `gobi vault publish` — Upload
|
|
39
|
-
- `gobi vault unpublish` — Delete
|
|
38
|
+
- `gobi vault publish` — Upload PUBLISH.md to the vault root on webdrive. Triggers post-processing (vault sync, metadata update, Discord notification).
|
|
39
|
+
- `gobi vault unpublish` — Delete PUBLISH.md from the vault on webdrive.
|
|
40
40
|
|
|
41
|
-
##
|
|
41
|
+
## PUBLISH.md Frontmatter Reference
|
|
42
42
|
|
|
43
|
-
`
|
|
43
|
+
`PUBLISH.md` is the metadata file at the root of every vault. Its YAML frontmatter controls the vault's public profile, homepage, and AI agent behavior. Example:
|
|
44
44
|
|
|
45
45
|
```yaml
|
|
46
46
|
---
|
|
@@ -49,7 +49,7 @@ tags:
|
|
|
49
49
|
- topic1
|
|
50
50
|
- topic2
|
|
51
51
|
description: A short description of what this vault is about.
|
|
52
|
-
thumbnail: "[[
|
|
52
|
+
thumbnail: "[[VAULT.png]]"
|
|
53
53
|
homepage: "[[app/home.html?nav=false]]"
|
|
54
54
|
prompt: "[[system-prompt.md]]"
|
|
55
55
|
---
|
|
@@ -69,7 +69,7 @@ prompt: "[[system-prompt.md]]"
|
|
|
69
69
|
# Inline array
|
|
70
70
|
tags: [ambient ai, wearables]
|
|
71
71
|
```
|
|
72
|
-
- **`thumbnail`** — Profile image for the vault card. Uses wiki-link syntax pointing to an image file in the vault (e.g. `"[[
|
|
72
|
+
- **`thumbnail`** — Profile image for the vault card. Uses wiki-link syntax pointing to an image file in the vault (e.g. `"[[VAULT.png]]"`).
|
|
73
73
|
- **`homepage`** — Custom HTML page to serve as the vault's public homepage at `gobispace.com/@{vaultSlug}`. Uses wiki-link syntax pointing to an HTML file in the vault. Supports a `nav` query parameter to control Gobi's sidebar navigation:
|
|
74
74
|
- `"[[app/home.html]]"` — Shows the Gobi sidebar alongside the homepage (default)
|
|
75
75
|
- `"[[app/home.html?nav=false]]"` — Full-screen, no Gobi sidebar/chrome
|
|
@@ -79,9 +79,9 @@ prompt: "[[system-prompt.md]]"
|
|
|
79
79
|
|
|
80
80
|
## Publishing Workflow
|
|
81
81
|
|
|
82
|
-
After editing `
|
|
82
|
+
After editing `PUBLISH.md` frontmatter, follow these steps to make your changes live:
|
|
83
83
|
|
|
84
|
-
1. **Edit `
|
|
84
|
+
1. **Edit `PUBLISH.md`** in the vault root with the desired frontmatter fields.
|
|
85
85
|
2. **Sync referenced files** — if the homepage HTML, thumbnail image, or prompt file is new or updated, upload them first:
|
|
86
86
|
```bash
|
|
87
87
|
gobi sync
|
|
@@ -90,10 +90,10 @@ After editing `BRAIN.md` frontmatter, follow these steps to make your changes li
|
|
|
90
90
|
```bash
|
|
91
91
|
gobi vault publish
|
|
92
92
|
```
|
|
93
|
-
This uploads `
|
|
93
|
+
This uploads `PUBLISH.md` to webdrive, triggers post-processing that extracts metadata (title, description, tags, thumbnail, homepage path), updates the vault's public profile, and sends a Discord notification.
|
|
94
94
|
4. The vault is now live at `https://gobispace.com/@{vaultSlug}`.
|
|
95
95
|
|
|
96
|
-
> **Important:** Any time you change `
|
|
96
|
+
> **Important:** Any time you change `PUBLISH.md` frontmatter (e.g. adding or updating `homepage`), you must re-run `gobi vault publish` for the changes to take effect.
|
|
97
97
|
|
|
98
98
|
## Reference Documentation
|
|
99
99
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
```
|
|
4
4
|
Usage: gobi vault [options] [command]
|
|
5
5
|
|
|
6
|
-
Vault commands. A Vault is your personal knowledge container — search public vaults, ask them questions, and publish
|
|
6
|
+
Vault commands. A Vault is your personal knowledge container — search public vaults, ask them questions, and publish a PUBLISH.md to make a vault public.
|
|
7
7
|
|
|
8
8
|
Options:
|
|
9
9
|
-h, --help display help for command
|
|
@@ -11,8 +11,8 @@ Options:
|
|
|
11
11
|
Commands:
|
|
12
12
|
search [options] Search public vaults by text and semantic similarity.
|
|
13
13
|
ask [options] Ask a vault a question. Creates a targeted session (1:1 conversation).
|
|
14
|
-
publish Upload
|
|
15
|
-
unpublish Delete
|
|
14
|
+
publish Upload PUBLISH.md to the vault root on webdrive. Triggers post-processing (vault sync, metadata update, Discord notification).
|
|
15
|
+
unpublish Delete PUBLISH.md from the vault on webdrive.
|
|
16
16
|
help [command] display help for command
|
|
17
17
|
```
|
|
18
18
|
|
|
@@ -48,7 +48,7 @@ Options:
|
|
|
48
48
|
```
|
|
49
49
|
Usage: gobi vault publish [options]
|
|
50
50
|
|
|
51
|
-
Upload
|
|
51
|
+
Upload PUBLISH.md to the vault root on webdrive. Triggers post-processing (vault sync, metadata update, Discord notification).
|
|
52
52
|
|
|
53
53
|
Options:
|
|
54
54
|
-h, --help display help for command
|
|
@@ -59,7 +59,7 @@ Options:
|
|
|
59
59
|
```
|
|
60
60
|
Usage: gobi vault unpublish [options]
|
|
61
61
|
|
|
62
|
-
Delete
|
|
62
|
+
Delete PUBLISH.md from the vault on webdrive.
|
|
63
63
|
|
|
64
64
|
Options:
|
|
65
65
|
-h, --help display help for command
|