@gobi-ai/cli 2.0.0 → 2.0.1

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.
@@ -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.3.8",
7
+ "version": "2.0.1",
8
8
  "plugins": [
9
9
  {
10
10
  "name": "gobi",
11
11
  "description": "Manage the Gobi collaborative knowledge platform from the command line. Publish vault profiles, create posts and replies, manage saved notes and posts, manage sessions, generate images and videos.",
12
- "version": "1.3.8",
12
+ "version": "2.0.1",
13
13
  "author": {
14
14
  "name": "gobi-ai"
15
15
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "gobi",
3
3
  "description": "Manage the Gobi collaborative knowledge platform from the command line",
4
- "version": "1.3.8",
4
+ "version": "2.0.1",
5
5
  "author": {
6
6
  "name": "gobi-ai"
7
7
  },
package/README.md CHANGED
@@ -4,7 +4,11 @@
4
4
  [![npm](https://img.shields.io/npm/v/@gobi-ai/cli)](https://www.npmjs.com/package/@gobi-ai/cli)
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
6
6
 
7
- Command-line interface for the [Gobi](https://gobispace.com) collaborative knowledge platform.
7
+ The programmatic interface to [Gobi](https://gobispace.com) the agent-facing surface of the ecosystem. The same capabilities the desktop and web clients use (auth, vault sync and publishing, personal posts and replies, saved knowledge, drafts, media generation, activity reads) exposed as composable shell commands so AI agents and developer scripts can participate in a user's Brain.
8
+
9
+ ## Why a CLI?
10
+
11
+ Most Gobi capabilities are interactive surfaces (Desktop, Web, Mobile). The CLI flips that: every command is scriptable, returns structured JSON when asked, and uses headless device-code auth so an agent can run it on any host. If you're building an agent that needs to read from or write to a user's Brain — capture notes, post to a community space, save a snippet, draft a suggestion, generate an image — this is the surface.
8
12
 
9
13
  ## Installation
10
14
 
@@ -34,10 +38,10 @@ npm link
34
38
  ## Quick start
35
39
 
36
40
  ```sh
37
- # Initialize — logs in and sets up your vault (creates PUBLISH.md)
41
+ # Initialize — log in and set up your vault (creates PUBLISH.md if missing)
38
42
  gobi init
39
43
 
40
- # Select a space
44
+ # Select a community space
41
45
  gobi space warp
42
46
 
43
47
  # Publish your vault profile (after editing PUBLISH.md frontmatter)
@@ -46,18 +50,71 @@ gobi vault publish
46
50
  # Sync local files with the webdrive
47
51
  gobi vault sync
48
52
 
49
- # Browse the global feed and create a post
53
+ # Browse the global feed and create a personal post
50
54
  gobi global feed
51
- gobi global create-post --title "Hello" --content "Trying gobi"
55
+ gobi global create-post --title "Hello" --content "Trying gobi" --vault-slug my-vault
56
+ ```
57
+
58
+ ---
59
+
60
+ ## Using gobi from an agent
61
+
62
+ Everything below applies whether you're building a Claude Code skill, an autonomous agent, or a shell script. The CLI was designed to be agent-driven first.
63
+
64
+ ### JSON envelope
65
+
66
+ Pass `--json` as a **global flag** (before the subcommand) and every command returns a structured envelope:
67
+
68
+ ```sh
69
+ gobi --json space list-posts
70
+ # {"success": true, "data": [...]}
71
+
72
+ gobi --json space get-post 99999
73
+ # {"success": false, "error": "Post not found"}
52
74
  ```
53
75
 
76
+ `success: true` always carries `data`; `success: false` always carries `error`. Pagination metadata (`pagination: { hasMore, nextCursor }`) ships alongside `data` on list endpoints. Skill docs and the `--help` output describe each command's `data` shape.
77
+
78
+ ### Context discovery
79
+
80
+ The CLI looks up two pieces of state:
81
+
82
+ | Path | What | Who manages |
83
+ |------|------|-------------|
84
+ | `~/.gobi/credentials.json` | Auth tokens (`accessToken`, `refreshToken`) | `gobi auth login` writes; `gobi auth logout` clears |
85
+ | `.gobi/settings.yaml` | Per-project `vaultSlug` and `selectedSpaceSlug` | `gobi init` and `gobi space warp` write |
86
+
87
+ An agent should check these before calling commands that need a vault or space:
88
+
89
+ ```sh
90
+ # Are we authenticated?
91
+ gobi --json auth status
92
+
93
+ # Discover the project's defaults
94
+ cat .gobi/settings.yaml 2>/dev/null
95
+ ```
96
+
97
+ If `.gobi/settings.yaml` is missing, `gobi init` and `gobi space warp` are the interactive entry points — they require user input, so an agent should hand off to the user rather than trying to drive them silently.
98
+
99
+ Every command that depends on a vault or space accepts an explicit override (`--vault-slug`, `--space-slug`) so an agent can act without ambient state.
100
+
101
+ ### Headless auth
102
+
103
+ `gobi auth login` is a device-code flow: it prints a URL and a user code to stdout, then polls. An agent can run it as a background task, surface the URL to the user as a clickable link, and wait for the process to exit. See [`commands/login.md`](commands/login.md) for the canonical agent recipe.
104
+
105
+ ### Per-session context for drafts
106
+
107
+ When the runtime exports `GOBI_SESSION_ID`, `gobi draft add` picks it up automatically — no need to pass `--session` from inside an agent run. See the **Drafts** section below.
108
+
109
+ ---
110
+
54
111
  ## Commands
55
112
 
56
113
  ### Authentication
57
114
 
58
115
  | Command | Description |
59
116
  |---------|-------------|
60
- | `gobi auth login` | Sign in via device code flow |
117
+ | `gobi auth login` | Sign in via device-code flow |
61
118
  | `gobi auth status` | Show current auth status |
62
119
  | `gobi auth logout` | Sign out and clear credentials |
63
120
 
@@ -75,7 +132,7 @@ gobi global create-post --title "Hello" --content "Trying gobi"
75
132
  |---------|-------------|
76
133
  | `gobi vault publish` | Upload `PUBLISH.md` to your vault. Triggers profile/metadata refresh. |
77
134
  | `gobi vault unpublish` | Remove `PUBLISH.md` from your vault. |
78
- | `gobi vault sync` | Sync local vault files with Gobi Webdrive. |
135
+ | `gobi vault sync` | Sync local vault files with Gobi WebDrive. |
79
136
 
80
137
  Public vaults are accessible at `https://gobispace.com/@{vaultSlug}`.
81
138
 
@@ -96,6 +153,8 @@ Public vaults are accessible at `https://gobispace.com/@{vaultSlug}`.
96
153
 
97
154
  ### Spaces
98
155
 
156
+ A *Space* is a community knowledge area. A *Space Post* lives in one space. The same `Post` data type, in a different scope, is a *Personal Post* (see Global feed below) — so anything you can do to a Space Post you can do to a Personal Post.
157
+
99
158
  > Space and member administration (creating spaces, inviting/approving members, joining/leaving) is web-UI only and not available in the CLI.
100
159
 
101
160
  | Command | Description |
@@ -106,29 +165,31 @@ Public vaults are accessible at `https://gobispace.com/@{vaultSlug}`.
106
165
  | `gobi space list-topic-posts <topicSlug>` | List posts tagged with a topic |
107
166
  | `gobi space list-posts` | List posts in the space |
108
167
  | `gobi space get-post <postId>` | Get a post with its ancestors and replies |
109
- | `gobi space create-post --title <t> --content <c>` | Create a post |
110
- | `gobi space edit-post <postId> [--title <t>] [--content <c>]` | Edit a post (at least one required) |
111
- | `gobi space delete-post <postId>` | Delete a post |
112
- | `gobi space create-reply <postId> --content <c>` | Reply to a post |
168
+ | `gobi space create-post --title <t> --content <c> [--vault-slug <slug>] [--auto-attachments]` | Create a space post. `--vault-slug` attributes it to a vault you own; `--auto-attachments` uploads `[[wikilinks]]` to that vault and uses it as `authorVaultSlug`. |
169
+ | `gobi space edit-post <postId> [--title <t>] [--content <c>] [--vault-slug <slug>] [--auto-attachments]` | Edit a space post. `--vault-slug ""` detaches the vault. |
170
+ | `gobi space delete-post <postId>` | Delete a space post |
171
+ | `gobi space create-reply <postId> --content <c>` | Reply to a space post |
113
172
  | `gobi space edit-reply <replyId> --content <c>` | Edit a reply |
114
173
  | `gobi space delete-reply <replyId>` | Delete a reply |
115
174
 
116
- ### Global feed
175
+ ### Global feed (personal posts)
117
176
 
118
- The global feed is the public, slugless feed of vault-authored posts visible across all spaces.
177
+ A *Personal Post* lives on the author's profile (their primary vault) and surfaces in the public global feed. Same `Post` model as a Space Post, scoped to the user instead of a space.
119
178
 
120
179
  | Command | Description |
121
180
  |---------|-------------|
122
181
  | `gobi global feed` | List the global public feed (posts + replies, newest first) |
123
- | `gobi global list-posts [--mine] [--vault-slug <slug>]` | List posts in the global feed |
124
- | `gobi global get-post <postId>` | Get a global post with its ancestors and replies |
125
- | `gobi global create-post [--title <t>] (--content <c> \| --rich-text <json>)` | Create a post in the global feed |
126
- | `gobi global edit-post <postId> [--title <t>] [--content <c>]` | Edit a post you authored |
127
- | `gobi global delete-post <postId>` | Delete a post you authored |
128
- | `gobi global create-reply <postId> (--content <c> \| --rich-text <json>)` | Reply to a global post |
182
+ | `gobi global list-posts [--mine] [--vault-slug <slug>]` | List personal posts; filter to your own or by author vault |
183
+ | `gobi global get-post <postId>` | Get a personal post with its ancestors and replies |
184
+ | `gobi global create-post [--title <t>] (--content <c> \| --rich-text <json>) [--vault-slug <slug>] [--auto-attachments]` | Create a personal post |
185
+ | `gobi global edit-post <postId> [--title <t>] [--content <c>] [--vault-slug <slug>]` | Edit a personal post you authored. `--vault-slug ""` detaches the vault. |
186
+ | `gobi global delete-post <postId>` | Delete a personal post you authored |
187
+ | `gobi global create-reply <postId> (--content <c> \| --rich-text <json>)` | Reply to a personal post |
129
188
  | `gobi global edit-reply <replyId> --content <c>` | Edit a reply you authored |
130
189
  | `gobi global delete-reply <replyId>` | Delete a reply you authored |
131
190
 
191
+ `--vault-slug` requires that the caller hold `role: 'owner'` on the target vault. When set, it becomes the post's `authorVaultSlug`. When `--auto-attachments` is set, the same vault is used both as the upload destination for `[[wikilinks]]` and as `authorVaultSlug`.
192
+
132
193
  ### Sessions
133
194
 
134
195
  | Command | Description |
@@ -141,6 +202,8 @@ The global feed is the public, slugless feed of vault-authored posts visible acr
141
202
 
142
203
  ### Sense
143
204
 
205
+ Activity and transcription data captured by Gobi Sense (or the mobile app).
206
+
144
207
  | Command | Description |
145
208
  |---------|-------------|
146
209
  | `gobi sense activities --start-time <iso> --end-time <iso>` | Fetch activity records in a time range |
@@ -159,7 +222,7 @@ Times are ISO 8601 UTC (e.g. `2026-03-20T00:00:00Z`).
159
222
  | `gobi saved note list [--date YYYY-MM-DD]` | List your notes (recent via cursor, or all for a day) |
160
223
  | `gobi saved note get <id>` | Get a single note |
161
224
  | `gobi saved note create --content <c>` | Create a note (use `-` to read content from stdin) |
162
- | `gobi saved note edit <id> [--content <c>] [--agent-id <id>]` | Edit a note (at least one required; `--agent-id null` clears the link) |
225
+ | `gobi saved note edit <id> [--content <c>] [--agent-id <id>]` | Edit a note (`--agent-id null` clears the link) |
163
226
  | `gobi saved note delete <id>` | Delete a note you authored |
164
227
 
165
228
  `saved note list` and `saved note create` accept `--timezone <iana>` (default: system timezone).
@@ -170,30 +233,46 @@ Times are ISO 8601 UTC (e.g. `2026-03-20T00:00:00Z`).
170
233
  |---------|-------------|
171
234
  | `gobi saved post list [--type all\|article\|space-post]` | List posts you've saved |
172
235
  | `gobi saved post get <postId>` | Get a saved post snapshot |
173
- | `gobi saved post create --source <id>` | Save a post or reply by id |
236
+ | `gobi saved post create --source <id>` | Save a post or reply by id (records a snapshot) |
174
237
  | `gobi saved post delete <postId>` | Remove a post from your saved collection |
175
238
 
176
239
  ### Drafts
177
240
 
178
- Drafts are authored by your agent during chat (or by external agents using `gobi draft add` as their tool layer). Each draft carries 0–3 AI-suggested actions the user can pick from. The top 5 pending drafts (lowest priority first) feed the agent's system prompt every turn. Every draft is anchored to the chat session that produced it.
241
+ A *draft* is a unit of standing guidance authored by an agent. Each draft carries 0–3 AI-suggested action labels the user picks from. The top 5 pending drafts (lowest priority first) are injected into the agent's system prompt every turn drafts turn agent suggestions into running context.
242
+
243
+ When invoked from inside an agent run, the runtime exports `GOBI_SESSION_ID` so `gobi draft add` picks it up automatically; otherwise pass `--session <uuid>`.
179
244
 
180
245
  | Command | Description |
181
246
  |---------|-------------|
182
247
  | `gobi draft list [--limit N]` | List drafts (priority ASC, then newest first) |
183
248
  | `gobi draft get <id>` | Show one draft with its history and suggested actions |
184
- | `gobi draft add <title> <content> [--session <id>] [--priority N] [--action <label>]…` | Add a draft. Pass `--action` up to 3 times to attach AI-suggested actions. `--session` falls back to `$GOBI_SESSION_ID`. Use `-` for content to read from stdin. |
249
+ | `gobi draft add <title> <content> [--session <id>] [--priority N] [--action <label>]…` | Add a draft. Pass `--action` up to 3 times. `--session` falls back to `$GOBI_SESSION_ID`. Use `-` for content to read from stdin. |
185
250
  | `gobi draft delete <id>` | Delete a draft |
186
251
  | `gobi draft prioritize <id> <priority>` | Set priority (lower = higher) |
187
252
  | `gobi draft action <id> <index>` | Take one of the draft's suggested actions by 0-based index. Marks `actioned` and posts the synthesized message into the originating session. |
188
253
  | `gobi draft revise <id> <comment> [--title <t>] [--content <c>] [--action <label>]…` | Bump revision with a comment; optionally replace title / content / actions in the same call |
189
254
 
255
+ ### Media generation
256
+
257
+ Image, video, and avatar generation. See the `gobi-media` skill for full workflows.
258
+
259
+ | Command | Description |
260
+ |---------|-------------|
261
+ | `gobi media image-generate --prompt <p> [--aspect-ratio <r>] [-o <file>]` | Generate an image (use `-o` to wait + download) |
262
+ | `gobi media image-edit --image <f> --prompt <p>` | Edit/inpaint an image |
263
+ | `gobi media video-create --avatar-id <a> --voice-id <v> --script <s>` | Avatar video with voice narration |
264
+ | `gobi media cinematic-create --prompt <p>` | Cinematic video from a text prompt |
265
+ | `gobi media avatar-design / avatar-from-selfie` | Custom avatars from prompts or selfies |
266
+ | `gobi media avatars` / `gobi media voices` | List available avatars and voices |
267
+ | `gobi media upload <file>` | Upload a local file and get a media id |
268
+
190
269
  ### Global options
191
270
 
192
271
  | Option | Scope | Description |
193
272
  |--------|-------|-------------|
194
- | `--json` | All commands | Output results as JSON |
273
+ | `--json` | All commands | Output structured JSON (`{success, data}` / `{success, error}`) |
195
274
  | `--space-slug <slug>` | `space` commands | Override the default space (from `.gobi/settings.yaml`) |
196
- | `--vault-slug <slug>` | Per-command | Override the default vault; available on post/reply commands that upload attachments and on `global create-post` |
275
+ | `--vault-slug <slug>` | Per-command | Override the default vault see each command's docs |
197
276
 
198
277
  ## Configuration
199
278
 
@@ -203,6 +282,7 @@ Drafts are authored by your agent during chat (or by external agents using `gobi
203
282
  |----------|---------|-------------|
204
283
  | `GOBI_BASE_URL` | `https://api.joingobi.com` | API server URL |
205
284
  | `GOBI_WEBDRIVE_BASE_URL` | `https://webdrive.joingobi.com` | File storage URL |
285
+ | `GOBI_SESSION_ID` | — | Default `--session` for `gobi draft add` (set automatically inside agent runs) |
206
286
 
207
287
  ### Files
208
288
 
@@ -210,8 +290,27 @@ Drafts are authored by your agent during chat (or by external agents using `gobi
210
290
  |------|-------------|
211
291
  | `~/.gobi/credentials.json` | Stored authentication tokens |
212
292
  | `.gobi/settings.yaml` | Per-project vault and space configuration |
293
+ | `.gobi/syncfiles` | Whitelist patterns for `gobi vault sync` (one per line) |
294
+ | `.gobi/sync.db` | Local sync state (cursor, hash cache) — managed by the CLI |
213
295
  | `PUBLISH.md` | Vault profile document with YAML frontmatter, published via `gobi vault publish` |
214
296
 
297
+ ## Claude Code skills
298
+
299
+ The CLI ships a `.claude-plugin/` manifest with eight skills that wrap the command groups for Claude Code agents:
300
+
301
+ | Skill | Covers |
302
+ |-------|--------|
303
+ | `gobi-core` | Auth, init, session, update, space list/warp |
304
+ | `gobi-vault` | `gobi vault publish/unpublish/sync` |
305
+ | `gobi-space` | `gobi space …` and `gobi global …` |
306
+ | `gobi-saved` | `gobi saved note …` and `gobi saved post …` |
307
+ | `gobi-draft` | `gobi draft …` |
308
+ | `gobi-media` | `gobi media …` |
309
+ | `gobi-sense` | `gobi sense activities/transcriptions` |
310
+ | `gobi-homepage` | Building custom HTML homepages with `window.gobi` |
311
+
312
+ Each skill's `SKILL.md` is hand-written orientation; `references/` is regenerated from `--help` output by `npm run generate-skill-docs`.
313
+
215
314
  ## Development
216
315
 
217
316
  ```sh
@@ -228,6 +327,8 @@ Run from source without compiling:
228
327
  npm run dev -- auth status
229
328
  ```
230
329
 
330
+ Tests run against `dist/*.test.js` (built JS), so `npm run build` is a prerequisite for `npm test`.
331
+
231
332
  ## License
232
333
 
233
334
  [MIT](LICENSE)
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: space-share
3
- description: Summarize recent learnings from this session and draft a vault post to share to the global feed.
3
+ description: Summarize recent learnings from this session and draft a personal post to share to the global feed.
4
4
  argument-hint: "[context]"
5
5
  ---
6
6
 
@@ -16,7 +16,7 @@ gobi --json auth status
16
16
 
17
17
  Check that `.gobi/settings.yaml` exists and contains both `vaultSlug` and `selectedSpaceSlug`. If not, stop and ask the user to run `gobi init` and `gobi space warp` first.
18
18
 
19
- ## Draft a vault post
19
+ ## Draft a personal post
20
20
 
21
21
  If `$ARGUMENTS` is provided, treat it as additional context or emphasis to guide the draft (e.g. "Emphasize the auth fix" or "Focus on the API design decision").
22
22
 
@@ -1,4 +1,5 @@
1
1
  import { existsSync, readFileSync, appendFileSync } from "fs";
2
+ import { EOL } from "os";
2
3
  import { join, extname } from "path";
3
4
  import ignore from "ignore";
4
5
  import { WEBDRIVE_BASE_URL } from "./constants.js";
@@ -33,7 +34,7 @@ function addToLocalSyncfiles(gobiDir, filePath) {
33
34
  if (isPathCovered(filePath, patterns))
34
35
  return;
35
36
  const syncfilesPath = join(gobiDir, "syncfiles");
36
- appendFileSync(syncfilesPath, `\n${filePath}`);
37
+ appendFileSync(syncfilesPath, `${EOL}${filePath}`);
37
38
  console.log(`Added to syncfiles: ${filePath}`);
38
39
  }
39
40
  export async function uploadAttachments(vaultSlug, links, token, options) {
@@ -1,9 +1,8 @@
1
- import { readFileSync } from "fs";
2
1
  import { apiDelete, apiGet, apiPatch, apiPost } from "../client.js";
3
- import { isJsonMode, jsonOut, unwrapResp } from "./utils.js";
2
+ import { isJsonMode, jsonOut, readStdin, unwrapResp } from "./utils.js";
4
3
  function readContent(value) {
5
4
  if (value === "-")
6
- return readFileSync("/dev/stdin", "utf8");
5
+ return readStdin();
7
6
  return value;
8
7
  }
9
8
  function snippet(content, max = 80) {
@@ -1,11 +1,10 @@
1
- import { readFileSync } from "fs";
2
1
  import { apiGet, apiPost, apiPatch, apiDelete } from "../client.js";
3
- import { isJsonMode, jsonOut, resolveVaultSlug, unwrapResp } from "./utils.js";
2
+ import { isJsonMode, jsonOut, readStdin, resolveVaultSlug, unwrapResp, } from "./utils.js";
4
3
  import { extractWikiLinks, uploadAttachments } from "../attachments.js";
5
4
  import { getValidToken } from "../auth/manager.js";
6
5
  function readContent(value) {
7
6
  if (value === "-")
8
- return readFileSync("/dev/stdin", "utf8");
7
+ return readStdin();
9
8
  return value;
10
9
  }
11
10
  function formatFeedLine(m) {
@@ -232,9 +231,13 @@ export function registerGlobalCommand(program) {
232
231
  .option("--title <title>", "New title")
233
232
  .option("--content <content>", "New content (markdown supported, use \"-\" for stdin)")
234
233
  .option("--rich-text <richText>", "Rich-text JSON array (mutually exclusive with --content)")
234
+ .option("--vault-slug <vaultSlug>", "Attribute the post to this vault (sets authorVaultId). Pass an empty string to detach.")
235
235
  .action(async (postId, opts) => {
236
- if (opts.title == null && opts.content == null && opts.richText == null) {
237
- throw new Error("Provide at least --title, --content, or --rich-text to update.");
236
+ if (opts.title == null &&
237
+ opts.content == null &&
238
+ opts.richText == null &&
239
+ opts.vaultSlug === undefined) {
240
+ throw new Error("Provide at least --title, --content, --rich-text, or --vault-slug to update.");
238
241
  }
239
242
  if (opts.content && opts.richText) {
240
243
  throw new Error("--content and --rich-text are mutually exclusive.");
@@ -254,6 +257,8 @@ export function registerGlobalCommand(program) {
254
257
  }
255
258
  body.richText = parsed;
256
259
  }
260
+ if (opts.vaultSlug !== undefined)
261
+ body.authorVaultSlug = opts.vaultSlug;
257
262
  const resp = (await apiPatch(`/posts/${postId}`, body));
258
263
  const post = unwrapResp(resp);
259
264
  if (isJsonMode(global)) {
@@ -1,6 +1,5 @@
1
- import { readFileSync } from "fs";
2
1
  import { apiGet, apiPost, apiPatch, apiDelete } from "../client.js";
3
- import { isJsonMode, jsonOut, unwrapResp } from "./utils.js";
2
+ import { isJsonMode, jsonOut, readStdin, unwrapResp } from "./utils.js";
4
3
  function defaultTimezone() {
5
4
  return Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
6
5
  }
@@ -101,7 +100,7 @@ function registerNoteCommands(saved) {
101
100
  if (!opts.content) {
102
101
  throw new Error("--content is required (use '-' to read from stdin)");
103
102
  }
104
- const content = opts.content === "-" ? readFileSync("/dev/stdin", "utf8") : opts.content;
103
+ const content = opts.content === "-" ? readStdin() : opts.content;
105
104
  const body = {
106
105
  content,
107
106
  timezone: opts.timezone || defaultTimezone(),
@@ -128,7 +127,7 @@ function registerNoteCommands(saved) {
128
127
  const body = {};
129
128
  if (opts.content != null) {
130
129
  body.content =
131
- opts.content === "-" ? readFileSync("/dev/stdin", "utf8") : opts.content;
130
+ opts.content === "-" ? readStdin() : opts.content;
132
131
  }
133
132
  if (opts.agentId != null) {
134
133
  body.agentId = opts.agentId === "null" ? null : parseInt(opts.agentId, 10);
@@ -1,12 +1,11 @@
1
- import { readFileSync } from "fs";
2
1
  import { apiGet, apiPost, apiPatch, apiDelete } from "../client.js";
3
2
  import { selectSpace, writeSpaceSetting } from "./init.js";
4
- import { isJsonMode, jsonOut, resolveSpaceSlug, resolveVaultSlug, unwrapResp } from "./utils.js";
3
+ import { isJsonMode, jsonOut, readStdin, resolveSpaceSlug, resolveVaultSlug, unwrapResp, } from "./utils.js";
5
4
  import { extractWikiLinks, uploadAttachments } from "../attachments.js";
6
5
  import { getValidToken } from "../auth/manager.js";
7
6
  function readContent(value) {
8
7
  if (value === "-")
9
- return readFileSync("/dev/stdin", "utf8");
8
+ return readStdin();
10
9
  return value;
11
10
  }
12
11
  function formatFeedLine(m) {
@@ -295,21 +294,27 @@ export function registerSpaceCommand(program) {
295
294
  .description("Create a post in a space.")
296
295
  .requiredOption("--title <title>", "Title of the post")
297
296
  .requiredOption("--content <content>", "Post content (markdown supported)")
298
- .option("--auto-attachments", "Upload wiki-linked [[files]] to webdrive before posting")
299
- .option("--vault-slug <vaultSlug>", "Vault slug for attachment uploads (overrides .gobi/settings.yaml)")
297
+ .option("--auto-attachments", "Upload wiki-linked [[files]] to webdrive before posting (also attributes the post to that vault)")
298
+ .option("--vault-slug <vaultSlug>", "Attribute the post to this vault (sets authorVaultId). Also used as upload destination for --auto-attachments.")
300
299
  .action(async (opts) => {
301
300
  const content = readContent(opts.content);
301
+ let authorVaultSlug;
302
+ if (opts.vaultSlug || opts.autoAttachments) {
303
+ authorVaultSlug = resolveVaultSlug(opts);
304
+ }
302
305
  if (opts.autoAttachments) {
303
- const vaultSlug = resolveVaultSlug(opts);
304
306
  const token = await getValidToken();
305
307
  const links = extractWikiLinks(content);
306
- await uploadAttachments(vaultSlug, links, token, { addToSyncfiles: true });
308
+ await uploadAttachments(authorVaultSlug, links, token, { addToSyncfiles: true });
307
309
  }
308
310
  const spaceSlug = resolveSpaceSlug(space);
309
- const resp = (await apiPost(`/spaces/${spaceSlug}/posts`, {
311
+ const body = {
310
312
  title: opts.title,
311
313
  content,
312
- }));
314
+ };
315
+ if (authorVaultSlug)
316
+ body.authorVaultSlug = authorVaultSlug;
317
+ const resp = (await apiPost(`/spaces/${spaceSlug}/posts`, body));
313
318
  const post = unwrapResp(resp);
314
319
  if (isJsonMode(space)) {
315
320
  jsonOut(post);
@@ -325,26 +330,36 @@ export function registerSpaceCommand(program) {
325
330
  .description("Edit a post. You must be the author.")
326
331
  .option("--title <title>", "New title for the post")
327
332
  .option("--content <content>", "New content for the post (markdown supported)")
328
- .option("--auto-attachments", "Upload wiki-linked [[files]] to webdrive before editing")
329
- .option("--vault-slug <vaultSlug>", "Vault slug for attachment uploads (overrides .gobi/settings.yaml)")
333
+ .option("--auto-attachments", "Upload wiki-linked [[files]] to webdrive before editing (also attributes the post to that vault)")
334
+ .option("--vault-slug <vaultSlug>", "Attribute the post to this vault (sets authorVaultId). Also used as upload destination for --auto-attachments. Pass an empty string to detach.")
330
335
  .action(async (postId, opts) => {
331
- if (!opts.title && !opts.content) {
332
- throw new Error("Provide at least --title or --content to update.");
336
+ const wantsVaultChange = opts.vaultSlug !== undefined || opts.autoAttachments;
337
+ if (!opts.title && !opts.content && !wantsVaultChange) {
338
+ throw new Error("Provide at least --title, --content, or --vault-slug to update.");
333
339
  }
334
340
  const spaceSlug = resolveSpaceSlug(space);
341
+ let authorVaultSlug;
342
+ if (opts.vaultSlug !== undefined) {
343
+ // Empty string detaches; non-empty resolves through settings fallback.
344
+ authorVaultSlug = opts.vaultSlug === "" ? "" : resolveVaultSlug(opts);
345
+ }
346
+ else if (opts.autoAttachments) {
347
+ authorVaultSlug = resolveVaultSlug(opts);
348
+ }
335
349
  const body = {};
336
350
  if (opts.title != null)
337
351
  body.title = opts.title;
338
352
  if (opts.content != null) {
339
353
  const content = readContent(opts.content);
340
354
  if (opts.autoAttachments) {
341
- const vaultSlug = resolveVaultSlug(opts);
342
355
  const token = await getValidToken();
343
356
  const links = extractWikiLinks(content);
344
- await uploadAttachments(vaultSlug, links, token, { addToSyncfiles: true });
357
+ await uploadAttachments(authorVaultSlug, links, token, { addToSyncfiles: true });
345
358
  }
346
359
  body.content = content;
347
360
  }
361
+ if (authorVaultSlug !== undefined)
362
+ body.authorVaultSlug = authorVaultSlug;
348
363
  const resp = (await apiPatch(`/spaces/${spaceSlug}/posts/${postId}`, body));
349
364
  const post = unwrapResp(resp);
350
365
  if (isJsonMode(space)) {
@@ -10,20 +10,26 @@ async function fetchLatestVersion() {
10
10
  const data = (await res.json());
11
11
  return data.version;
12
12
  }
13
- function detectInstallMethod() {
13
+ // `which` is Unix-only; Windows uses `where`. `where` may print multiple
14
+ // matches on separate lines — take the first one.
15
+ function locateGobi() {
16
+ const cmd = process.platform === "win32" ? "where gobi" : "which gobi";
14
17
  try {
15
- const gobiBin = execSync("which gobi", { encoding: "utf-8" }).trim();
16
- if (gobiBin.includes("/Cellar/") || gobiBin.includes("/homebrew/")) {
17
- return "brew";
18
- }
18
+ const out = execSync(cmd, { encoding: "utf-8" }).trim();
19
+ return out.split(/\r?\n/)[0] || null;
19
20
  }
20
21
  catch {
21
- // ignore
22
+ return null;
23
+ }
24
+ }
25
+ function detectInstallMethod() {
26
+ const gobiBin = locateGobi();
27
+ if (gobiBin && (gobiBin.includes("/Cellar/") || gobiBin.includes("/homebrew/"))) {
28
+ return "brew";
22
29
  }
23
30
  try {
24
31
  const npmGlobalDir = execSync("npm root -g", { encoding: "utf-8" }).trim();
25
- const gobiBin = execSync("which gobi", { encoding: "utf-8" }).trim();
26
- if (gobiBin.includes(npmGlobalDir.replace("/lib/node_modules", ""))) {
32
+ if (gobiBin && gobiBin.includes(npmGlobalDir.replace("/lib/node_modules", ""))) {
27
33
  return "npm";
28
34
  }
29
35
  }
@@ -1,4 +1,10 @@
1
+ import { readFileSync } from "fs";
1
2
  import { getSpaceSlug, getVaultSlug } from "./init.js";
3
+ // Reads all of stdin synchronously. Uses fd 0 (cross-platform) instead of
4
+ // "/dev/stdin", which doesn't exist on Windows.
5
+ export function readStdin() {
6
+ return readFileSync(0, "utf8");
7
+ }
2
8
  export function isJsonMode(cmd) {
3
9
  return !!cmd.parent?.opts().json;
4
10
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gobi-ai/cli",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "CLI client for the Gobi collaborative knowledge platform",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -2,19 +2,19 @@
2
2
  name: gobi-core
3
3
  description: >-
4
4
  Core Gobi CLI: authentication (login/logout/status), vault initialization
5
- (gobi init), space selection (gobi space warp/list), file sync (gobi sync),
6
- CLI updates (gobi update), and session management (list/get/reply to
7
- conversations). Use when the user needs to set up Gobi, authenticate,
8
- sync files, manage sessions, or update the CLI.
5
+ (gobi init), space selection (gobi space warp/list), CLI updates (gobi
6
+ update), and session management (list/get/reply to conversations). Use when
7
+ the user needs to set up Gobi, authenticate, manage sessions, or update the
8
+ CLI. File sync is in the gobi-vault skill.
9
9
  allowed-tools: Bash(gobi:*)
10
10
  metadata:
11
11
  author: gobi-ai
12
- version: "0.8.0"
12
+ version: "2.0.0"
13
13
  ---
14
14
 
15
15
  # gobi-core
16
16
 
17
- Core CLI commands for the Gobi collaborative knowledge platform (v0.8.0).
17
+ Core CLI commands for the Gobi collaborative knowledge platform (v2.0.0).
18
18
 
19
19
  ## Prerequisites
20
20
 
@@ -38,8 +38,11 @@ brew tap gobi-ai/tap && brew install gobi
38
38
 
39
39
  ## Key Concepts
40
40
 
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 posts, replies, sessions, and connected vaults.
42
- - **Vault**: A filetree storage of information and knowledge. 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`). Configure a vault's public profile with a `PUBLISH.md` document and `gobi vault publish`.
41
+ - **Vault**: A filetree-backed knowledge home. A local directory becomes a vault when it contains `.gobi/settings.yaml` with a `vaultSlug`. Each vault has a slug (e.g. `brave-path-zr962w`); public profile is configured by a `PUBLISH.md` document at the vault root and pushed via `gobi vault publish`.
42
+ - **Personal Post**: A post on the author's profile that surfaces in the public global feed. Same `Post` data model as a Space Post only the scope differs.
43
+ - **Space Post**: A post inside a community space.
44
+ - **Space**: A shared community knowledge area. A user can be a member of one or more spaces; each space contains posts, replies, sessions, and connected vaults.
45
+ - **Draft**: A unit of standing guidance authored by an agent during chat. Each draft carries 0–3 AI-suggested actions the user picks from. The top 5 pending drafts feed the agent's system prompt every turn.
43
46
 
44
47
  ## First-Time Setup
45
48
 
@@ -85,7 +88,7 @@ Check auth status anytime:
85
88
  gobi auth status
86
89
  ```
87
90
 
88
- **Important for agents**: Before running any `space` command, check if `.gobi/settings.yaml` exists in the current directory with both `vaultSlug` and `selectedSpaceSlug`. If the vault is missing, guide the user through `gobi init`. If only the space is missing, guide the user through `gobi space warp`. These commands require user input (interactive prompts), so the agent cannot run them silently.
91
+ **Important for agents**: Before running any `space` command, check whether `.gobi/settings.yaml` exists in the current directory with both `vaultSlug` and `selectedSpaceSlug`. If the vault is missing, guide the user through `gobi init`. If only the space is missing, guide the user through `gobi space warp`. These commands require user input (interactive prompts), so the agent cannot run them silently. For one-off calls, every command also accepts an explicit `--vault-slug` / `--space-slug` override.
89
92
 
90
93
  ## Important: JSON Mode
91
94
 
@@ -95,7 +98,7 @@ For programmatic/agent usage, always pass `--json` as a **global** option (befor
95
98
  gobi --json session list
96
99
  ```
97
100
 
98
- JSON responses have the shape `{ "success": true, "data": ... }` on success or `{ "success": false, "error": "..." }` on failure.
101
+ JSON responses have the shape `{ "success": true, "data": ... }` on success or `{ "success": false, "error": "..." }` on failure. Pagination metadata (`pagination: { hasMore, nextCursor }`) ships alongside `data` on list endpoints.
99
102
 
100
103
  ## Available Commands
101
104
 
@@ -110,15 +113,17 @@ JSON responses have the shape `{ "success": true, "data": ... }` on success or `
110
113
  - `gobi session get` — Get a session and its messages (paginated).
111
114
  - `gobi session list` — List all sessions you are part of, sorted by most recent activity.
112
115
  - `gobi session reply` — Send a human reply to a session you are a member of.
113
- - `gobi vault sync` — Sync local vault files with Gobi Webdrive.
114
116
  - `gobi update` — Update gobi-cli to the latest version.
115
117
 
118
+ > File sync (`gobi vault sync`) lives in the **gobi-vault** skill.
119
+
116
120
  ## Reference Documentation
117
121
 
118
122
  - [gobi auth](references/auth.md)
119
123
  - [gobi init](references/init.md)
120
124
  - [gobi session](references/session.md)
121
125
  - [gobi update](references/update.md)
126
+ - [gobi space (list/warp)](references/space.md)
122
127
 
123
128
  ## Configuration Files
124
129
 
@@ -134,3 +139,4 @@ JSON responses have the shape `{ "success": true, "data": ... }` on success or `
134
139
  |----------|---------|-------------|
135
140
  | `GOBI_BASE_URL` | `https://api.joingobi.com` | API server URL |
136
141
  | `GOBI_WEBDRIVE_BASE_URL` | `https://webdrive.joingobi.com` | File storage URL |
142
+ | `GOBI_SESSION_ID` | — | Default `--session` for `gobi draft add` (set automatically inside agent runs) |
@@ -10,12 +10,12 @@ description: >-
10
10
  allowed-tools: Bash(gobi:*)
11
11
  metadata:
12
12
  author: gobi-ai
13
- version: "1.4.0"
13
+ version: "2.0.0"
14
14
  ---
15
15
 
16
16
  # gobi-draft
17
17
 
18
- Gobi draft commands for managing agent-authored drafts (v1.4.0).
18
+ Gobi draft commands for managing agent-authored drafts (v2.0.0).
19
19
 
20
20
  Requires gobi-cli installed and authenticated. See gobi-core skill for setup.
21
21
 
@@ -52,7 +52,7 @@ For programmatic/agent usage, always pass `--json` as a **global** option (befor
52
52
 
53
53
  ```bash
54
54
  gobi --json draft list --limit 20
55
- gobi --json draft add "Concise titles" "Prefer concise titles for vault posts." --action "Apply" --action "Skip" --priority 50
55
+ gobi --json draft add "Concise titles" "Prefer concise titles for personal posts." --action "Apply" --action "Skip" --priority 50
56
56
  gobi --json draft action <draftId> 0
57
57
  ```
58
58
 
@@ -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, vault posts, and chat.
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, personal posts, 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
 
@@ -67,10 +67,12 @@ function getFileUrl(path) {
67
67
  }
68
68
  ```
69
69
 
70
- ### Vault posts
70
+ ### Personal posts
71
+
72
+ > `listVaultPosts` is still accepted as a deprecated alias for back-compat with older homepages — existing applets won't break, but new code should use `listPersonalPosts`.
71
73
 
72
74
  ```js
73
- const { data: updates, pagination } = await gobi.listVaultPosts({ limit: 10, cursor: null });
75
+ const { data: updates, pagination } = await gobi.listPersonalPosts({ limit: 10, cursor: null });
74
76
  // updates[i] → {
75
77
  // id: 42,
76
78
  // title: 'New insights',
@@ -88,7 +90,7 @@ for (const u of updates) {
88
90
  // Pagination — load the next page using the cursor
89
91
  if (pagination.hasMore) {
90
92
  const { data: moreUpdates, pagination: nextPage } =
91
- await gobi.listVaultPosts({ limit: 10, cursor: pagination.nextCursor });
93
+ await gobi.listPersonalPosts({ limit: 10, cursor: pagination.nextCursor });
92
94
  }
93
95
  ```
94
96
 
@@ -175,7 +177,7 @@ renderer.link = (href, title, text) =>
175
177
  marked.setOptions({ renderer });
176
178
  ```
177
179
 
178
- **Plain-text previews.** For BU list 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.
180
+ **Plain-text previews.** For post list 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
181
 
180
182
  ---
181
183
 
@@ -202,9 +204,9 @@ Centralize colors and spacing in CSS custom properties so restyling is a one-lin
202
204
 
203
205
  Pair with Google Fonts (e.g. Space Grotesk for headings, IBM Plex Mono for meta, Inter for body) via CDN `<link>`.
204
206
 
205
- ### Knowledge Graph from BU topics
207
+ ### Knowledge Graph from post topics
206
208
 
207
- Vault posts carry a `topics` array. Treat each topic as a node and any two topics co-occurring in the same post 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).
209
+ Personal posts carry a `topics` array. Treat each topic as a node and any two topics co-occurring in the same post 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
210
 
209
211
  ```js
210
212
  // Separate data-building from rendering so the same graph can be drawn at multiple sizes.
@@ -246,7 +248,7 @@ function drawGraph(containerId, w, h, data, opts = {}) {
246
248
  ```
247
249
 
248
250
  Tips:
249
- - **Enrich the data.** One page of 8 BUs makes a sparse graph. Paginate 3–4 times (cap at ~32 BUs) before building.
251
+ - **Enrich the data.** One page of 8 posts makes a sparse graph. Paginate 3–4 times (cap at ~32 posts) before building.
250
252
  - **Cache the built data** in a module-level variable so the full-screen overlay can reuse it without refetching.
251
253
  - **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
254
  - 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.
@@ -272,7 +274,7 @@ function openOverlay(renderInto) {
272
274
 
273
275
  Always restore `body.overflow` on close, and always remove the `keydown` listener.
274
276
 
275
- ### Vault post card — preview/full toggle
277
+ ### Personal post card — preview/full toggle
276
278
 
277
279
  Show a truncated card that expands in place on click:
278
280
 
@@ -389,11 +391,11 @@ Single breakpoint at `768px` is enough for most homepages:
389
391
  `https://gobispace.com/login?redirect_uri=${encodeURIComponent(window.location.href)}`;
390
392
  }
391
393
 
392
- // ── Vault posts ──────────────────────────────────
394
+ // ── Personal posts ───────────────────────────────
393
395
 
394
396
  async function loadUpdates() {
395
397
  try {
396
- const { data: updates } = await gobi.listVaultPosts({ limit: 5 });
398
+ const { data: updates } = await gobi.listPersonalPosts({ limit: 5 });
397
399
  const el = document.getElementById('updates');
398
400
  for (const u of updates) {
399
401
  const div = document.createElement('div');
@@ -402,7 +404,7 @@ Single breakpoint at `768px` is enough for most homepages:
402
404
  el.appendChild(div);
403
405
  }
404
406
  } catch (err) {
405
- console.error('Failed to load vault posts:', err);
407
+ console.error('Failed to load personal posts:', err);
406
408
  }
407
409
  }
408
410
 
@@ -10,12 +10,12 @@ description: >-
10
10
  allowed-tools: Bash(gobi:*)
11
11
  metadata:
12
12
  author: gobi-ai
13
- version: "0.8.0"
13
+ version: "2.0.0"
14
14
  ---
15
15
 
16
16
  # gobi-media
17
17
 
18
- Gobi media generation commands (v0.8.0).
18
+ Gobi media generation commands (v2.0.0).
19
19
 
20
20
  Requires gobi-cli installed and authenticated. See gobi-core skill for setup.
21
21
 
@@ -9,12 +9,12 @@ description: >-
9
9
  allowed-tools: Bash(gobi:*)
10
10
  metadata:
11
11
  author: gobi-ai
12
- version: "1.3.9"
12
+ version: "2.0.0"
13
13
  ---
14
14
 
15
15
  # gobi-saved
16
16
 
17
- Gobi saved-knowledge commands (v1.3.9).
17
+ Gobi saved-knowledge commands (v2.0.0).
18
18
 
19
19
  Requires gobi-cli installed and authenticated. See gobi-core skill for setup.
20
20
 
@@ -7,23 +7,27 @@ description: >-
7
7
  allowed-tools: Bash(gobi:*)
8
8
  metadata:
9
9
  author: gobi-ai
10
- version: "0.8.0"
10
+ version: "2.0.0"
11
11
  ---
12
12
 
13
13
  # gobi-sense
14
14
 
15
- Gobi sense commands for activity and transcription data (v0.8.0).
15
+ Gobi sense commands for activity and transcription data (v2.0.0).
16
16
 
17
- Requires gobi-cli installed and authenticated. See gobi-core skill for setup.
17
+ Requires gobi-cli installed and authenticated. See the **gobi-core** skill for setup.
18
+
19
+ Activities and transcriptions are captured by Gobi Sense (the wearable) and the mobile app, then ingested via the cloud pipeline. The CLI surface is read-only — fetch records in a time range and feed them to whatever analysis you want to run.
18
20
 
19
21
  ## Important: JSON Mode
20
22
 
21
23
  For programmatic/agent usage, always pass `--json` as a **global** option (before the subcommand):
22
24
 
23
25
  ```bash
24
- gobi --json sense activities --from 2024-01-01 --to 2024-01-31
26
+ gobi --json sense activities --start-time 2026-04-01T00:00:00Z --end-time 2026-04-08T00:00:00Z
25
27
  ```
26
28
 
29
+ Times are ISO 8601 UTC.
30
+
27
31
  ## Available Commands
28
32
 
29
33
  - `gobi sense activities` — Fetch activity records within a time range.
@@ -1,29 +1,42 @@
1
1
  ---
2
2
  name: gobi-space
3
3
  description: >-
4
- Gobi space and global commands: read and write posts and replies, browse
5
- the unified feed and topic feeds, in a specific space or in the global
6
- public feed. Use when the user wants to read or write posts and replies
7
- in their Gobi community. Space and member administration is web-UI only.
4
+ Gobi space and global commands: read and write posts and replies, browse the
5
+ unified feed and topic feeds in a community space (`gobi space`) or in the
6
+ public global feed of personal posts (`gobi global`). Personal Posts and
7
+ Space Posts share the same data model; only the scope differs. Use when the
8
+ user wants to read or write posts and replies. Space and member admin is
9
+ web-UI only.
8
10
  allowed-tools: Bash(gobi:*)
9
11
  metadata:
10
12
  author: gobi-ai
11
- version: "0.9.13"
13
+ version: "2.0.0"
12
14
  ---
13
15
 
14
16
  # gobi-space
15
17
 
16
- Gobi space and global commands for community interaction (v0.9.13).
18
+ Gobi space and global posts (v2.0.0).
17
19
 
18
- Requires gobi-cli installed and authenticated. See gobi-core skill for setup.
20
+ Requires gobi-cli installed and authenticated. See the **gobi-core** skill for setup.
19
21
 
20
- ## Gobi Space Community Channel
22
+ ## Two scopes, one data model
21
23
 
22
- `gobi space` is the main interface for posts within a single space. `gobi global` is the same surface but for posts in the public global feed (no slug). When the user wants to engage with their community — use these commands.
24
+ The same `Post` data type drives both surfaces the difference is **scope**:
25
+
26
+ - **Space Post** — `gobi space …` — lives in a community space's feed.
27
+ - **Personal Post** — `gobi global …` — lives on the author's profile (their primary vault) and surfaces in the public global feed.
28
+
29
+ Anything you can do to a Space Post (reply, edit, delete, attribute to a vault) you can do to a Personal Post.
23
30
 
24
31
  - When the user wants to explore or catch up on what's happening in their space, invoke `/gobi:space-explore`.
25
32
  - When the user wants to share or post learnings from the current session, invoke `/gobi:space-share`.
26
33
 
34
+ ## Author vault attribution (`--vault-slug`)
35
+
36
+ Both `gobi space create-post` / `edit-post` and `gobi global create-post` / `edit-post` accept `--vault-slug <slug>`. When set, the slug becomes the post's `authorVaultSlug` — the vault the user is posting on behalf of. The caller must hold `role: 'owner'` on that vault. Pass `--vault-slug ""` on edit to detach.
37
+
38
+ `--auto-attachments` resolves a vault for upload and **also** uses it as `authorVaultSlug` automatically — one flag, two effects.
39
+
27
40
  ## Space Slug Override
28
41
 
29
42
  `gobi space` commands use the space from `.gobi/settings.yaml`. Override it with a parent-level flag:
@@ -55,28 +68,29 @@ gobi --json space list-posts
55
68
  ### Feed
56
69
  - `gobi space feed` — List the unified feed (posts and replies, newest first).
57
70
 
58
- ### Posts
71
+ ### Space posts
59
72
  - `gobi space list-posts` — List posts in a space (paginated).
60
73
  - `gobi space get-post <postId>` — Get a post with its ancestors and replies (paginated). Ancestors and replies are returned together; there is no separate `ancestors` or `list-replies` command.
61
- - `gobi space create-post` — Create a post in a space.
62
- - `gobi space edit-post <postId>` — Edit a post. You must be the author.
63
- - `gobi space delete-post <postId>` — Delete a post. You must be the author.
74
+ - `gobi space create-post` — Create a space post. `--vault-slug` attributes it to a vault you own; `--auto-attachments` uploads `[[wikilinks]]` to that vault and uses it as `authorVaultSlug`.
75
+ - `gobi space edit-post <postId>` — Edit a space post. You must be the author. `--vault-slug ""` detaches the vault.
76
+ - `gobi space delete-post <postId>` — Delete a space post. You must be the author.
64
77
 
65
- ### Replies
66
- - `gobi space create-reply <postId>` — Create a reply to a post in a space.
78
+ ### Space replies
79
+ - `gobi space create-reply <postId>` — Create a reply to a space post.
67
80
  - `gobi space edit-reply <replyId>` — Edit a reply. You must be the author.
68
81
  - `gobi space delete-reply <replyId>` — Delete a reply. You must be the author.
69
82
 
70
- ### Global feed
71
- `gobi global` is the same surface, but operates on the public global feed (no space slug). Posts are vault-authored and visible across all spaces.
83
+ ### Personal posts (global feed)
84
+
85
+ `gobi global` is the same surface for Personal Posts — posts that live on the author's profile and surface in the public global feed.
72
86
 
73
- - `gobi global feed` — List the global public feed (posts and replies, newest first).
74
- - `gobi global list-posts` — List posts in the global feed. Pass `--mine` for your own posts; `--vault-slug <slug>` to filter by vault.
75
- - `gobi global get-post <postId>` — Get a global post with its ancestors and replies.
76
- - `gobi global create-post` — Create a post in the global feed (publishes from your vault).
77
- - `gobi global edit-post <postId>` — Edit a post you authored.
78
- - `gobi global delete-post <postId>` — Delete a post you authored.
79
- - `gobi global create-reply <postId>` — Reply to a post in the global feed.
87
+ - `gobi global feed` — List the public global feed (posts and replies, newest first).
88
+ - `gobi global list-posts` — List personal posts. `--mine` for your own; `--vault-slug <slug>` to filter by author vault.
89
+ - `gobi global get-post <postId>` — Get a personal post with its ancestors and replies.
90
+ - `gobi global create-post` — Create a personal post. `--vault-slug` and `--auto-attachments` work the same as on `space create-post`.
91
+ - `gobi global edit-post <postId>` — Edit a personal post you authored. `--vault-slug ""` detaches the vault.
92
+ - `gobi global delete-post <postId>` — Delete a personal post you authored.
93
+ - `gobi global create-reply <postId>` — Reply to a personal post.
80
94
  - `gobi global edit-reply <replyId>` — Edit a reply you authored.
81
95
  - `gobi global delete-reply <replyId>` — Delete a reply you authored.
82
96
 
@@ -88,10 +88,11 @@ Usage: gobi global edit-post [options] <postId>
88
88
  Edit a post you authored in the global feed.
89
89
 
90
90
  Options:
91
- --title <title> New title
92
- --content <content> New content (markdown supported, use "-" for stdin)
93
- --rich-text <richText> Rich-text JSON array (mutually exclusive with --content)
94
- -h, --help display help for command
91
+ --title <title> New title
92
+ --content <content> New content (markdown supported, use "-" for stdin)
93
+ --rich-text <richText> Rich-text JSON array (mutually exclusive with --content)
94
+ --vault-slug <vaultSlug> Attribute the post to this vault (sets authorVaultId). Pass an empty string to detach.
95
+ -h, --help display help for command
95
96
  ```
96
97
 
97
98
  ## delete-post
@@ -112,8 +112,8 @@ Create a post in a space.
112
112
  Options:
113
113
  --title <title> Title of the post
114
114
  --content <content> Post content (markdown supported)
115
- --auto-attachments Upload wiki-linked [[files]] to webdrive before posting
116
- --vault-slug <vaultSlug> Vault slug for attachment uploads (overrides .gobi/settings.yaml)
115
+ --auto-attachments Upload wiki-linked [[files]] to webdrive before posting (also attributes the post to that vault)
116
+ --vault-slug <vaultSlug> Attribute the post to this vault (sets authorVaultId). Also used as upload destination for --auto-attachments.
117
117
  -h, --help display help for command
118
118
  ```
119
119
 
@@ -127,8 +127,8 @@ Edit a post. You must be the author.
127
127
  Options:
128
128
  --title <title> New title for the post
129
129
  --content <content> New content for the post (markdown supported)
130
- --auto-attachments Upload wiki-linked [[files]] to webdrive before editing
131
- --vault-slug <vaultSlug> Vault slug for attachment uploads (overrides .gobi/settings.yaml)
130
+ --auto-attachments Upload wiki-linked [[files]] to webdrive before editing (also attributes the post to that vault)
131
+ --vault-slug <vaultSlug> Attribute the post to this vault (sets authorVaultId). Also used as upload destination for --auto-attachments. Pass an empty string to detach.
132
132
  -h, --help display help for command
133
133
  ```
134
134
 
@@ -7,12 +7,12 @@ description: >-
7
7
  allowed-tools: Bash(gobi:*)
8
8
  metadata:
9
9
  author: gobi-ai
10
- version: "0.9.13"
10
+ version: "2.0.0"
11
11
  ---
12
12
 
13
13
  # gobi-vault
14
14
 
15
- Gobi vault commands for publishing your vault profile and syncing files (v0.9.13).
15
+ Gobi vault commands for publishing your vault profile and syncing files (v2.0.0).
16
16
 
17
17
  Requires gobi-cli installed and authenticated. See gobi-core skill for setup.
18
18