@gobi-ai/cli 2.0.21 → 2.0.23

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": "2.0.21",
7
+ "version": "2.0.23",
8
8
  "plugins": [
9
9
  {
10
10
  "name": "gobi",
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": "2.0.21",
11
+ "description": "Manage the Gobi collaborative knowledge platform from the command line. Publish vault profiles, create posts and replies, generate images and videos.",
12
+ "version": "2.0.23",
13
13
  "author": {
14
14
  "name": "gobi-ai"
15
15
  },
@@ -19,7 +19,6 @@
19
19
  "./skills/gobi-core",
20
20
  "./skills/gobi-space",
21
21
  "./skills/gobi-vault",
22
- "./skills/gobi-saved",
23
22
  "./skills/gobi-draft",
24
23
  "./skills/gobi-media",
25
24
  "./skills/gobi-sense",
@@ -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": "2.0.21",
4
+ "version": "2.0.23",
5
5
  "author": {
6
6
  "name": "gobi-ai"
7
7
  },
@@ -10,7 +10,6 @@
10
10
  "./skills/gobi-core",
11
11
  "./skills/gobi-space",
12
12
  "./skills/gobi-vault",
13
- "./skills/gobi-saved",
14
13
  "./skills/gobi-draft",
15
14
  "./skills/gobi-media",
16
15
  "./skills/gobi-sense",
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 Gobi AI
3
+ Copyright (c) 2025-2026 Gobi AI
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -4,11 +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
- 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.
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, drafts, media generation, activity reads) exposed as composable shell commands so AI agents and developer scripts can act on a user's behalf in Gobi.
8
8
 
9
9
  ## Why a CLI?
10
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.
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 work in a user's Gobi — capture notes, post to a community space, draft a suggestion, generate an image — this is the surface.
12
12
 
13
13
  ## Installation
14
14
 
@@ -63,7 +63,7 @@ Each setup step unlocks a different family of commands — run only the ones the
63
63
  | Step | Unlocks |
64
64
  |------|---------|
65
65
  | `gobi auth login` | All authenticated commands |
66
- | `gobi vault init` | Every `gobi vault …` command (`publish`, `unpublish`, `sync`) and lets `global create-post` default to that vault |
66
+ | `gobi vault init` | Every `gobi vault …` command (`publish`, `unpublish`, `sync`); also lets `global create-post --auto-attachments` resolve that vault automatically |
67
67
  | `gobi space warp` | Every `gobi space …` command without needing `--space-slug` |
68
68
 
69
69
  ---
@@ -142,6 +142,10 @@ When the runtime exports `GOBI_SESSION_ID`, `gobi draft add` picks it up automat
142
142
 
143
143
  | Command | Description |
144
144
  |---------|-------------|
145
+ | `gobi vault create <slug> --name <n>` | Create a new vault. Does not change the configured vault — run `gobi vault init` or `gobi vault set-primary` afterwards if you want to anchor to it. |
146
+ | `gobi vault rename <newName> [--vault-slug <slug>]` | Rename a vault. Defaults to the configured vault. Local display name only — does not affect `PUBLISH.md` frontmatter. |
147
+ | `gobi vault delete <slug>` | Delete a vault. Irreversible. The API rejects if the vault still owns content; clean up posts, members, and files first. |
148
+ | `gobi vault set-primary <slug>` | Mark a vault as your primary. Unsets primary on the others. |
145
149
  | `gobi vault publish` | Upload `PUBLISH.md` to your vault. Triggers profile/metadata refresh. |
146
150
  | `gobi vault unpublish` | Remove `PUBLISH.md` from your vault. |
147
151
  | `gobi vault status [--vault-slug <slug>]` | Show the configured vault's publish state (`isPublished`), profile fields, file count, and public profile URL. Useful as a pre-flight check before posting with `--auto-attachments`. |
@@ -178,40 +182,48 @@ A *Space* is a community knowledge area. A *Space Post* lives in one space. The
178
182
  | `gobi space list-topic-posts <topicSlug>` | List posts tagged with a topic |
179
183
  | `gobi space list-posts` | List posts in the space |
180
184
  | `gobi space get-post <postId> [--full]` | Get a post with its ancestors and replies. `--full` shows reply content without truncation. |
181
- | `gobi space create-post --title <t> --content <c> [--vault-slug <slug>] [--auto-attachments] [--draft-id <id>]` | 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`. `--draft-id` links the post back to a draft (records `postId`/`spaceSlug` on `draft.metadata` so the client can render an "Open post" button). |
185
+ | `gobi space create-post [--title <t>] (--content <c> \| --rich-text <json> \| --draft-id <id>) [--vault-slug <slug>] [--auto-attachments] [--repost-post-id <id>] [--attach <file>]…` | Create a space post. Must provide content via one of `--content`, `--rich-text`, or `--draft-id`. `--vault-slug` attributes it to a vault you own; `--auto-attachments` uploads `[[wikilinks]]` to that vault and uses it as `authorVaultSlug`. `--draft-id` links the post back to a draft (records `postId`/`spaceSlug` on `draft.metadata` so the client can render an "Open post" button). `--repost-post-id` reposts an existing post (sets `repostPostId` on the new post). `--attach` uploads local media to render inline in-feed (repeatable; X-style mix rule — up to 4 photos OR 1 GIF OR 1 video). |
182
186
  | `gobi space edit-post <postId> [--title <t>] [--content <c>] [--vault-slug <slug>] [--auto-attachments]` | Edit a space post. `--vault-slug ""` detaches the vault. |
183
187
  | `gobi space delete-post <postId>` | Delete a space post |
184
- | `gobi space create-reply <postId> (--content <c> \| --rich-text <json>) [--vault-slug <slug>] [--auto-attachments]` | Create a reply to a space post |
188
+ | `gobi space create-reply <postId> (--content <c> \| --rich-text <json>) [--vault-slug <slug>] [--auto-attachments] [--attach <file>]…` | Create a reply to a space post. `--attach` works the same as on `create-post`. |
185
189
  | `gobi space edit-reply <replyId> [--content <c>] [--rich-text <json>] [--vault-slug <slug>] [--auto-attachments]` | Edit a reply you authored. `--vault-slug ""` detaches attribution. |
186
190
  | `gobi space delete-reply <replyId>` | Delete a reply you authored |
187
191
 
188
192
  ### Global feed (personal posts)
189
193
 
190
- 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.
194
+ A *Personal Post* surfaces in the public global feed. Pass `--vault-slug` to attribute it to a vault you own (it'll then surface on that vault's profile too); with no `--vault-slug` and no `--auto-attachments` the post has no `authorVaultSlug` and lives only on the global feed. Same `Post` model as a Space Post, scoped to the user instead of a space.
191
195
 
192
196
  | Command | Description |
193
197
  |---------|-------------|
194
198
  | `gobi global feed [--following]` | List the global public feed (posts + replies, newest first). `--following` limits to authors you follow. |
195
199
  | `gobi global list-posts [--mine] [--vault-slug <slug>]` | List personal posts; filter to your own or by author vault |
196
200
  | `gobi global get-post <postId> [--full]` | Get a personal post with its ancestors and replies. `--full` shows reply content without truncation. |
197
- | `gobi global create-post [--title <t>] (--content <c> \| --rich-text <json>) [--vault-slug <slug>] [--auto-attachments] [--draft-id <id>]` | Create a personal post. `--draft-id` links the post back to a draft (records `postId` on `draft.metadata`). |
201
+ | `gobi global create-post [--title <t>] (--content <c> \| --rich-text <json>) [--vault-slug <slug>] [--auto-attachments] [--draft-id <id>] [--repost-post-id <id>] [--attach <file>]…` | Create a personal post. `--draft-id` links the post back to a draft (records `postId` on `draft.metadata`). `--repost-post-id` reposts an existing post. `--attach` uploads local media for inline rendering (see `gobi space create-post` above for the mix rule). |
198
202
  | `gobi global edit-post <postId> [--title <t>] [--content <c>] [--vault-slug <slug>]` | Edit a personal post you authored. `--vault-slug ""` detaches the vault. |
199
203
  | `gobi global delete-post <postId>` | Delete a personal post you authored |
200
- | `gobi global create-reply <postId> (--content <c> \| --rich-text <json>) [--vault-slug <slug>] [--auto-attachments]` | Create a reply to a personal post |
204
+ | `gobi global create-reply <postId> (--content <c> \| --rich-text <json>) [--vault-slug <slug>] [--auto-attachments] [--attach <file>]…` | Create a reply to a personal post |
201
205
  | `gobi global edit-reply <replyId> [--content <c>] [--rich-text <json>] [--vault-slug <slug>] [--auto-attachments]` | Edit a reply you authored. `--vault-slug ""` detaches attribution. |
202
206
  | `gobi global delete-reply <replyId>` | Delete a reply you authored |
203
207
 
204
208
  `--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`.
205
209
 
206
- ### Sessions
210
+ ### Personal space (private posts)
211
+
212
+ > Naming note: a **Personal Post** (under `gobi global`, above) is the public-feed kind — it lives on your vault profile and surfaces on the global feed. A **personal-space post** (this section, under `gobi personal`) is the private kind — same `Post` data model, but scoped via `personalSpaceUserId` so only you can see it.
213
+
214
+ Private posts and replies visible only to you. Same `Post` data model and subcommand shape as `gobi global`, but scoped to a personal space — they never appear on the public global feed.
207
215
 
208
216
  | Command | Description |
209
217
  |---------|-------------|
210
- | `gobi session list` | List your sessions |
211
- | `gobi session get <id>` | Get a session and its messages |
212
- | `gobi session create-reply <id> --content <c>` | Send a message in a session |
213
-
214
- `session create-reply` also accepts `--rich-text <json>` (mutually exclusive with `--content`).
218
+ | `gobi personal feed` | Your personal-space feed (posts + replies, newest first) |
219
+ | `gobi personal list-posts` | List personal-space posts |
220
+ | `gobi personal get-post <postId> [--full]` | Get a personal-space post with its ancestors and replies |
221
+ | `gobi personal create-post [--title <t>] (--content <c> \| --rich-text <json>) [--vault-slug <slug>] [--auto-attachments] [--draft-id <id>] [--repost-post-id <id>] [--attach <file>]…` | Create a private post in your personal space. `--vault-slug` attributes it to a vault you own. `--attach` works the same as on `gobi global create-post`. |
222
+ | `gobi personal edit-post <postId> [--title <t>] [--content <c>] [--vault-slug <slug>] [--auto-attachments]` | Edit a personal-space post you authored |
223
+ | `gobi personal delete-post <postId>` | Delete a personal-space post you authored |
224
+ | `gobi personal create-reply <postId> (--content <c> \| --rich-text <json>) [--vault-slug <slug>] [--auto-attachments] [--attach <file>]…` | Reply to a personal-space post (inherits the parent's private scope) |
225
+ | `gobi personal edit-reply <replyId> [--content <c>] [--rich-text <json>] [--vault-slug <slug>] [--auto-attachments]` | Edit a reply you authored |
226
+ | `gobi personal delete-reply <replyId>` | Delete a reply you authored |
215
227
 
216
228
  ### Sense
217
229
 
@@ -224,31 +236,6 @@ Activity and transcription data captured by Gobi Sense (or the mobile app).
224
236
 
225
237
  Times are ISO 8601 UTC (e.g. `2026-03-20T00:00:00Z`).
226
238
 
227
- ### Saved
228
-
229
- `gobi saved` is the user's personal saved-knowledge collection — notes you author and posts you bookmark.
230
-
231
- #### Saved notes
232
-
233
- | Command | Description |
234
- |---------|-------------|
235
- | `gobi saved list-notes [--date YYYY-MM-DD]` | List your notes (recent via cursor, or all for a day) |
236
- | `gobi saved get-note <id>` | Get a single note |
237
- | `gobi saved create-note --content <c>` | Create a note (use `-` to read content from stdin) |
238
- | `gobi saved edit-note <id> [--content <c>] [--agent-id <id>]` | Edit a note (`--agent-id null` clears the link) |
239
- | `gobi saved delete-note <id>` | Delete a note you authored |
240
-
241
- `saved list-notes` and `saved create-note` accept `--timezone <iana>` (default: system timezone).
242
-
243
- #### Saved posts (bookmarks)
244
-
245
- | Command | Description |
246
- |---------|-------------|
247
- | `gobi saved list-posts [--type all\|article\|space-post]` | List posts you've bookmarked |
248
- | `gobi saved get-post <postId>` | Get a saved post snapshot |
249
- | `gobi saved create-post --source <id>` | Bookmark a post or reply by id (records a snapshot) |
250
- | `gobi saved delete-post <postId>` | Remove a post from your saved collection |
251
-
252
239
  ### Drafts
253
240
 
254
241
  A *draft* is a unit of standing guidance authored by an agent. Each draft carries 0–3 AI-suggested actions 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.
@@ -261,11 +248,11 @@ Each action is `{ label, message? }`: `label` is the short button text (1–80 c
261
248
  |---------|-------------|
262
249
  | `gobi draft list [--limit N]` | List drafts (priority ASC, then newest first) |
263
250
  | `gobi draft get <id>` | Get one draft with its history and suggested actions |
264
- | `gobi draft add <title> <content> [--session <id>] [--priority N] [--action <label[::message]>]…` | Add a draft. Pass `--action` up to 3 times; each action is `Label` or `Label::Message`. `--session` falls back to `$GOBI_SESSION_ID`. Use `-` for content to read from stdin. |
251
+ | `gobi draft add <title> <content> [--session <id>] [--vault-slug <slug>] [--priority N] [--action <label[::message]>]…` | Add a draft. Pass `--action` up to 3 times; each action is `Label` or `Label::Message`. `--session` falls back to `$GOBI_SESSION_ID`. `--vault-slug` anchors the draft to a specific vault (must be one you own). Use `-` for content to read from stdin. |
265
252
  | `gobi draft delete <id>` | Delete a draft |
266
253
  | `gobi draft prioritize <id> <priority>` | Set priority (lower = higher) |
267
254
  | `gobi draft action <id> <index>` | Take one of the draft's suggested actions by 0-based index. Marks `actioned` and posts the action's `message` (or `label`, if no message) into the originating session. |
268
- | `gobi draft revise <id> <comment> [--title <t>] [--content <c>] [--action <label[::message]>]…` | Bump revision with a comment; optionally replace title / content / actions in the same call |
255
+ | `gobi draft revise <id> <comment> [--title <t>] [--content <c>] [--vault-slug <slug>] [--action <label[::message]>]…` | Bump revision with a comment; optionally replace title / content / vault-slug / actions in the same call |
269
256
 
270
257
  ### Media generation
271
258
 
@@ -276,9 +263,12 @@ Image, video, and avatar generation. See the `gobi-media` skill for full workflo
276
263
  | `gobi media generate-image --prompt <p> [--aspect-ratio <r>] [-o <file>]` | Generate an image (use `-o` to wait + download) |
277
264
  | `gobi media edit-image --image <f> --prompt <p>` | Edit an image with a prompt |
278
265
  | `gobi media inpaint-image --image <f> --mask <m> --prompt <p>` | Inpaint a masked region |
266
+ | `gobi media get-image-status <jobId>` / `download-image <jobId>` | Poll an image job or download the result |
279
267
  | `gobi media create-video --avatar-id <a> --voice-id <v> --script <s>` | Avatar video with voice narration |
280
268
  | `gobi media create-cinematic --prompt <p>` | Cinematic video from a text prompt |
281
- | `gobi media design-avatar / design-avatar-from-selfie` | Custom avatars from prompts or selfies |
269
+ | `gobi media get-video-status <videoId>` / `download-video <videoId>` | Poll a video job or download the result |
270
+ | `gobi media design-avatar / design-avatar-from-selfie / confirm-avatar` | Custom avatars from prompts or selfies; confirm a variant after design |
271
+ | `gobi media get-avatar-job-status <jobId>` | Poll an avatar design job |
282
272
  | `gobi media list-avatars` / `gobi media list-voices` | List available avatars and voices |
283
273
  | `gobi media list-videos` / `gobi media get-video <id>` | List or get videos |
284
274
  | `gobi media upload <file>` | Upload a local file and get a media id |
@@ -287,7 +277,7 @@ Image, video, and avatar generation. See the `gobi-media` skill for full workflo
287
277
 
288
278
  | Option | Scope | Description |
289
279
  |--------|-------|-------------|
290
- | `--json` | All commands | Output structured JSON (`{success, data}` / `{success, error}`) |
280
+ | `--json` | All non-interactive commands | Output structured JSON (`{success, data}` / `{success, error}`). Interactive commands (`gobi auth login`, `gobi vault init`, `gobi update`, `gobi space warp` without a slug) prompt, poll, or stream subprocess output and ignore `--json`. |
291
281
  | `--space-slug <slug>` | `space` commands | Override the default space (from `.gobi/settings.yaml`) |
292
282
  | `--vault-slug <slug>` | Per-command | Override the default vault — see each command's docs |
293
283
 
@@ -299,6 +289,7 @@ Image, video, and avatar generation. See the `gobi-media` skill for full workflo
299
289
  |----------|---------|-------------|
300
290
  | `GOBI_BASE_URL` | `https://api.joingobi.com` | API server URL |
301
291
  | `GOBI_WEBDRIVE_BASE_URL` | `https://webdrive.joingobi.com` | File storage URL |
292
+ | `GOBI_WEB_BASE_URL` | `https://gobispace.com` | Public web URL (used when assembling shareable links) |
302
293
  | `GOBI_SESSION_ID` | — | Default `--session` for `gobi draft add` (set automatically inside agent runs) |
303
294
 
304
295
  ### Files
@@ -313,14 +304,13 @@ Image, video, and avatar generation. See the `gobi-media` skill for full workflo
313
304
 
314
305
  ## Claude Code skills
315
306
 
316
- The CLI ships a `.claude-plugin/` manifest with eight skills that wrap the command groups for Claude Code agents:
307
+ The CLI ships a `.claude-plugin/` manifest with skills that wrap the command groups for Claude Code agents:
317
308
 
318
309
  | Skill | Covers |
319
310
  |-------|--------|
320
- | `gobi-core` | Auth, session, update, space list/warp |
311
+ | `gobi-core` | Auth, update, space list/warp |
321
312
  | `gobi-vault` | `gobi vault init/list/publish/unpublish/sync` |
322
- | `gobi-space` | `gobi space …` and `gobi global …` |
323
- | `gobi-saved` | `gobi saved list-notes/create-note/list-posts/create-post/…` |
313
+ | `gobi-space` | `gobi space …`, `gobi global …`, and `gobi personal …` |
324
314
  | `gobi-draft` | `gobi draft …` |
325
315
  | `gobi-media` | `gobi media …` |
326
316
  | `gobi-sense` | `gobi sense list-activities/list-transcriptions` |
@@ -188,11 +188,11 @@ export function registerGlobalCommand(program) {
188
188
  // ── Create post ──
189
189
  global
190
190
  .command("create-post")
191
- .description("Create a post in the global feed. --vault-slug attributes it to a vault you own; defaults to your primary vault.")
191
+ .description("Create a post in the global feed. --vault-slug attributes it to a vault you own. With no --vault-slug and no --auto-attachments, the post is created without an authorVaultSlug (vault-less personal post).")
192
192
  .option("--title <title>", "Title of the post")
193
193
  .option("--content <content>", "Post content (markdown supported, use \"-\" for stdin)")
194
194
  .option("--rich-text <richText>", "Rich-text JSON array (mutually exclusive with --content)")
195
- .option("--vault-slug <vaultSlug>", "Attribute the post to this vault (sets authorVaultSlug). Defaults to your primary vault.")
195
+ .option("--vault-slug <vaultSlug>", "Attribute the post to this vault (sets authorVaultSlug). Caller must own the vault.")
196
196
  .option("--auto-attachments", "Upload wiki-linked [[files]] to webdrive before posting (also sets authorVaultSlug to that vault)")
197
197
  .option("--draft-id <draftId>", "Use this draft as the source of title and content (mutually exclusive with --title/--content/--rich-text). On success, links the post back by recording postId on draft.metadata so the client can render an 'Open post' button. The draft's vaultSlug seeds --vault-slug when not given explicitly.")
198
198
  .option("--attach <file>", "Local media file to attach. Repeatable. X-style mix rule: up to 4 photos OR 1 GIF OR 1 video. Size ceilings: 5MB photos / 15MB GIFs / 512MB video.", (value, prev = []) => [...prev, value], [])
@@ -216,7 +216,7 @@ export function registerMediaCommand(program) {
216
216
  ` ID: ${downloadId}\n` +
217
217
  ` Status: ${status}`);
218
218
  if (status === "inference_complete") {
219
- console.log(` Download: gobi media video-download ${downloadId}`);
219
+ console.log(` Download: gobi media download-video ${downloadId}`);
220
220
  }
221
221
  });
222
222
  media
@@ -418,7 +418,7 @@ export function registerMediaCommand(program) {
418
418
  ` ID: ${downloadId}\n` +
419
419
  ` Status: ${status}`);
420
420
  if (status === "inference_complete") {
421
- console.log(` Download: gobi media video-download ${downloadId}`);
421
+ console.log(` Download: gobi media download-video ${downloadId}`);
422
422
  }
423
423
  });
424
424
  // ════════════════════════════════════════════════════════════════════
@@ -632,7 +632,7 @@ export function registerMediaCommand(program) {
632
632
  console.log(` Download URL: ${imgUrl}`);
633
633
  }
634
634
  else if (status === "queued" || status === "inference_started" || status === "inference_working") {
635
- console.log(` Check: gobi media image-status ${jobId}`);
635
+ console.log(` Check: gobi media get-image-status ${jobId}`);
636
636
  }
637
637
  });
638
638
  media
@@ -190,7 +190,7 @@ export function registerPersonalCommand(program) {
190
190
  .option("--title <title>", "Title of the post")
191
191
  .option("--content <content>", "Post content (markdown supported, use \"-\" for stdin)")
192
192
  .option("--rich-text <richText>", "Rich-text JSON array (mutually exclusive with --content)")
193
- .option("--vault-slug <vaultSlug>", "Attribute the post to this vault (sets authorVaultSlug). Defaults to your primary vault.")
193
+ .option("--vault-slug <vaultSlug>", "Attribute the post to this vault (sets authorVaultSlug). Caller must own the vault.")
194
194
  .option("--auto-attachments", "Upload wiki-linked [[files]] to webdrive before posting (also sets authorVaultSlug to that vault)")
195
195
  .option("--draft-id <draftId>", "Use this draft as the source of title and content (mutually exclusive with --title/--content/--rich-text). On success, links the post back via draft.metadata. The draft's vaultSlug seeds --vault-slug when not given explicitly.")
196
196
  .option("--attach <file>", "Local media file to attach. Repeatable. X-style mix rule: up to 4 photos OR 1 GIF OR 1 video. Size ceilings: 5MB photos / 15MB GIFs / 512MB video.", (value, prev = []) => [...prev, value], [])
@@ -317,7 +317,7 @@ export function registerSpaceCommand(program) {
317
317
  .option("--content <content>", "Post content (markdown supported, use \"-\" for stdin)")
318
318
  .option("--rich-text <richText>", "Rich-text JSON array (mutually exclusive with --content)")
319
319
  .option("--auto-attachments", "Upload wiki-linked [[files]] to webdrive before posting (also attributes the post to that vault)")
320
- .option("--vault-slug <vaultSlug>", "Attribute the post to this vault (sets authorVaultId). Also used as upload destination for --auto-attachments.")
320
+ .option("--vault-slug <vaultSlug>", "Attribute the post to this vault (sets authorVaultSlug). Also used as upload destination for --auto-attachments.")
321
321
  .option("--space-slug <spaceSlug>", "Space slug (overrides .gobi/settings.yaml)")
322
322
  .option("--draft-id <draftId>", "Use this draft as the source of title and content (mutually exclusive with --title/--content/--rich-text). On success, links the post back by recording postId/spaceSlug on draft.metadata so the client can render an 'Open post' button. The draft's vaultSlug seeds --vault-slug when not given explicitly.")
323
323
  .option("--attach <file>", "Local media file to attach. Repeatable. X-style mix rule: up to 4 photos OR 1 GIF OR 1 video. Size ceilings: 5MB photos / 15MB GIFs / 512MB video.", (value, prev = []) => [...prev, value], [])
@@ -414,7 +414,7 @@ export function registerSpaceCommand(program) {
414
414
  .option("--content <content>", "New content for the post (markdown supported, use \"-\" for stdin)")
415
415
  .option("--rich-text <richText>", "Rich-text JSON array (mutually exclusive with --content)")
416
416
  .option("--auto-attachments", "Upload wiki-linked [[files]] to webdrive before editing (also attributes the post to that vault)")
417
- .option("--vault-slug <vaultSlug>", "Attribute the post to this vault (sets authorVaultId). Also used as upload destination for --auto-attachments.")
417
+ .option("--vault-slug <vaultSlug>", "Attribute the post to this vault (sets authorVaultSlug). Also used as upload destination for --auto-attachments.")
418
418
  .option("--space-slug <spaceSlug>", "Space slug (overrides .gobi/settings.yaml)")
419
419
  .action(async (postId, opts) => {
420
420
  const wantsVaultChange = !!(opts.vaultSlug || opts.autoAttachments);
@@ -409,13 +409,26 @@ export async function runSync(opts) {
409
409
  basePrivatePatterns = [...currPrivatePatterns];
410
410
  }
411
411
  const privatefilesChanges = computeSyncfilesChanges(basePrivatePatterns, currPrivatePatterns);
412
- // Walk local files (only whitelisted, non-ignored)
413
- if (!jsonMode)
414
- process.stdout.write("Scanning local files...");
415
- const localFiles = walkLocalFiles(vaultDir, state.hashCache, isWhitelisted);
416
- if (!jsonMode)
417
- console.log(` ${localFiles.length} file(s) found.`);
418
- const localPathSet = new Set(localFiles.map((f) => f.path));
412
+ // Walk local files (only whitelisted, non-ignored).
413
+ // Optimization: in download-only mode, skip the full walk + hash. The server
414
+ // will return its own file list via the cursor; we then hash only the files
415
+ // the server tells us about that also exist locally, avoiding work for files
416
+ // that are local-only and irrelevant to a download.
417
+ let localFiles = [];
418
+ let localPathSet = new Set();
419
+ const tWalk = Date.now();
420
+ if (opts.downloadOnly) {
421
+ process.stderr.write(`[gobi-sync] timing walkLocalFiles: skipped (download-only)\n`);
422
+ }
423
+ else {
424
+ if (!jsonMode)
425
+ process.stdout.write("Scanning local files...");
426
+ localFiles = walkLocalFiles(vaultDir, state.hashCache, isWhitelisted);
427
+ if (!jsonMode)
428
+ console.log(` ${localFiles.length} file(s) found.`);
429
+ localPathSet = new Set(localFiles.map((f) => f.path));
430
+ process.stderr.write(`[gobi-sync] timing walkLocalFiles: ${localFiles.length} files in ${Date.now() - tWalk}ms\n`);
431
+ }
419
432
  // Detect and send offline deletions
420
433
  let maxMutationCursor = null;
421
434
  for (const cachedPath of Object.keys(state.hashCache)) {
@@ -444,17 +457,22 @@ export async function runSync(opts) {
444
457
  }
445
458
  // In dry-run mode, include cached-but-locally-deleted files in clientFiles so the
446
459
  // server does not propagate the deletion (the whole point of dry-run is no changes).
447
- const clientFilesForSync = opts.dryRun
448
- ? [
449
- ...localFiles,
450
- ...Object.entries(state.hashCache)
451
- .filter(([p]) => !localPathSet.has(p) && !existsSync(join(vaultDir, p)))
452
- .map(([path, entry]) => ({ path, hash: entry.hash, mtime: entry.mtime })),
453
- ]
454
- : localFiles;
460
+ // In download-only mode, send no clientFiles — the lazy-hash filter below decides
461
+ // per-file whether we already have the server's version.
462
+ const clientFilesForSync = opts.downloadOnly
463
+ ? []
464
+ : opts.dryRun
465
+ ? [
466
+ ...localFiles,
467
+ ...Object.entries(state.hashCache)
468
+ .filter(([p]) => !localPathSet.has(p) && !existsSync(join(vaultDir, p)))
469
+ .map(([path, entry]) => ({ path, hash: entry.hash, mtime: entry.mtime })),
470
+ ]
471
+ : localFiles;
455
472
  // POST sync request
456
473
  if (!jsonMode)
457
474
  process.stdout.write("Syncing with server...");
475
+ const tSync = Date.now();
458
476
  let syncResp;
459
477
  try {
460
478
  syncResp = await performSync(baseUrl, vaultSlug, state, syncfilesChanges, privatefilesChanges, clientFilesForSync, opts, token);
@@ -480,6 +498,38 @@ export async function runSync(opts) {
480
498
  }
481
499
  if (!jsonMode)
482
500
  console.log(` ${syncResp.files.length} action(s).`);
501
+ process.stderr.write(`[gobi-sync] timing performSync: ${syncResp.files.length} actions in ${Date.now() - tSync}ms\n`);
502
+ // Lazy hash filter for download-only: the server returned its file list, but
503
+ // some of those files may already exist locally with the same hash (the common
504
+ // case for a re-activation of an already-synced vault). Drop those actions so
505
+ // we don't redownload identical bytes. hashFile short-circuits via mtime+size
506
+ // when state.hashCache has a matching entry, so warm caches stay cheap.
507
+ if (opts.downloadOnly) {
508
+ const tFilter = Date.now();
509
+ let hashed = 0;
510
+ let alreadyHave = 0;
511
+ syncResp.files = syncResp.files.filter((f) => {
512
+ if (f.action !== "download" || !f.hash)
513
+ return true;
514
+ const absPath = join(vaultDir, f.path);
515
+ if (!existsSync(absPath))
516
+ return true;
517
+ try {
518
+ const entry = hashFile(absPath, f.path, state.hashCache);
519
+ hashed++;
520
+ state.hashCache[f.path] = entry;
521
+ if (entry.hash === f.hash) {
522
+ alreadyHave++;
523
+ return false;
524
+ }
525
+ return true;
526
+ }
527
+ catch {
528
+ return true;
529
+ }
530
+ });
531
+ process.stderr.write(`[gobi-sync] timing downloadFilter: hashed ${hashed}, dropped ${alreadyHave} already-matching, ${syncResp.files.length} remain in ${Date.now() - tFilter}ms\n`);
532
+ }
483
533
  // Write plan file if requested (dry-run + --plan-file)
484
534
  if (opts.dryRun && opts.planFile) {
485
535
  const offlineDeletions = Object.keys(state.hashCache).filter((p) => !localPathSet.has(p) && !existsSync(join(vaultDir, p)));
@@ -167,7 +167,7 @@ export function registerVaultCommand(program) {
167
167
  requireVault(statusCmd);
168
168
  const publishCmd = vault
169
169
  .command("publish")
170
- .description(`Upload ${PUBLISH_FILENAME} to the vault root on webdrive. Triggers post-processing (vault sync, metadata update, Discord notification).`)
170
+ .description(`Upload ${PUBLISH_FILENAME} to the vault root on webdrive. Triggers post-processing (vault sync, metadata update).`)
171
171
  .action(async () => {
172
172
  const vaultId = getVaultSlug();
173
173
  const filePath = join(process.cwd(), PUBLISH_FILENAME);
package/dist/main.js CHANGED
@@ -8,8 +8,6 @@ import { registerSpaceCommand } from "./commands/space.js";
8
8
  import { registerGlobalCommand } from "./commands/global.js";
9
9
  import { registerPersonalCommand } from "./commands/personal.js";
10
10
  import { registerVaultCommand } from "./commands/vault.js";
11
- import { registerSavedCommand } from "./commands/saved.js";
12
- import { registerSessionsCommand } from "./commands/sessions.js";
13
11
  import { registerSenseCommand } from "./commands/sense.js";
14
12
  import { registerUpdateCommand } from "./commands/update.js";
15
13
  import { registerMediaCommand } from "./commands/media.js";
@@ -63,8 +61,6 @@ export async function cli() {
63
61
  registerGlobalCommand(program);
64
62
  registerPersonalCommand(program);
65
63
  registerVaultCommand(program);
66
- registerSavedCommand(program);
67
- registerSessionsCommand(program);
68
64
  registerSenseCommand(program);
69
65
  registerUpdateCommand(program);
70
66
  registerMediaCommand(program);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gobi-ai/cli",
3
- "version": "2.0.21",
3
+ "version": "2.0.23",
4
4
  "description": "CLI client for the Gobi collaborative knowledge platform",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -2,19 +2,18 @@
2
2
  name: gobi-core
3
3
  description: >-
4
4
  Core Gobi CLI: authentication (login/logout/status), space selection (gobi
5
- space warp/list), CLI updates (gobi update), and session management
6
- (list/get/reply to conversations). Use when the user needs to authenticate,
7
- manage sessions, or update the CLI. Vault setup is in the gobi-vault skill;
8
- file sync is also in gobi-vault.
5
+ space warp/list), and CLI updates (gobi update). Use when the user needs to
6
+ authenticate or update the CLI. Vault setup is in the gobi-vault skill; file
7
+ sync is also in gobi-vault.
9
8
  allowed-tools: Bash(gobi:*)
10
9
  metadata:
11
10
  author: gobi-ai
12
- version: "2.0.9"
11
+ version: "2.0.23"
13
12
  ---
14
13
 
15
14
  # gobi-core
16
15
 
17
- Core CLI commands for the Gobi collaborative knowledge platform (v2.0.9).
16
+ Core CLI commands for the Gobi collaborative knowledge platform (v2.0.23).
18
17
 
19
18
  ## Prerequisites
20
19
 
@@ -41,7 +40,7 @@ brew tap gobi-ai/tap && brew install gobi
41
40
  - **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
41
  - **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
42
  - **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.
43
+ - **Space**: A shared community knowledge area. A user can be a member of one or more spaces; each space contains posts, replies, and connected vaults.
45
44
  - **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.
46
45
 
47
46
  ## Setup steps (run only what you need)
@@ -51,7 +50,7 @@ There is **no `gobi init`** command — each setup step is its own command, and
51
50
  | Step | Command | Unlocks |
52
51
  |------|---------|---------|
53
52
  | 1. Log in | `gobi auth login` | All authenticated commands |
54
- | 2. Configure a vault for this directory | `gobi vault init` | Every `gobi vault …` command + lets `global create-post` default to this vault |
53
+ | 2. Configure a vault for this directory | `gobi vault init` | Every `gobi vault …` command; also lets `global create-post --auto-attachments` resolve that vault automatically |
55
54
  | 3. Pick an active space for this directory | `gobi space warp` | Every `gobi space …` post/reply/feed command without needing `--space-slug` |
56
55
 
57
56
  After step 2 + step 3, `.gobi/settings.yaml` looks like:
@@ -73,7 +72,7 @@ gobi auth status
73
72
 
74
73
  | Command family | Needs vault in `.gobi`? | Needs space in `.gobi`? | Per-call override |
75
74
  |----------------|------------------------|------------------------|-------------------|
76
- | `auth …`, `update`, `session …`, `saved …`, `draft …`, `media …`, `sense …` | no | no | – |
75
+ | `auth …`, `update`, `draft …`, `media …`, `sense …` | no | no | – |
77
76
  | `vault publish` / `unpublish` / `sync` | **yes** | no | none — must run `gobi vault init` first |
78
77
  | `vault init` | no (it sets it up) | no | – |
79
78
  | `space list` / `warp [slug]` / `get [slug]` | no | no | – |
@@ -81,6 +80,9 @@ gobi auth status
81
80
  | `global feed` / `list-posts` / `get-post` / `delete-post` / `create-reply` / `edit-reply` / `delete-reply` | no | no | – |
82
81
  | `global create-post` | optional¹ | no | command-level `--vault-slug <slug>` |
83
82
  | `global edit-post` | optional² | no | command-level `--vault-slug <slug>` |
83
+ | `personal feed` / `list-posts` / `get-post` / `delete-post` / `create-reply` / `edit-reply` / `delete-reply` | no | no | – |
84
+ | `personal create-post` | optional¹ | no | command-level `--vault-slug <slug>` |
85
+ | `personal edit-post` | optional² | no | command-level `--vault-slug <slug>` |
84
86
 
85
87
  ¹ `global create-post` accepts `--vault-slug` and `--auto-attachments`, both optional. With neither flag and no `vaultSlug` in `.gobi`, the post is created with no `authorVaultSlug` (vault-less personal post) — same as a Space post that isn't attributed to any vault. Set `--vault-slug` (or have `vaultSlug` in `.gobi` plus pass `--auto-attachments`) to attribute it.
86
88
 
@@ -93,7 +95,7 @@ When a command needs vault or space and neither `.gobi` nor an override flag pro
93
95
  For programmatic/agent usage, always pass `--json` as a **global** option (before the subcommand) to get structured JSON output:
94
96
 
95
97
  ```bash
96
- gobi --json session list
98
+ gobi --json space list
97
99
  ```
98
100
 
99
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.
@@ -106,26 +108,19 @@ JSON responses have the shape `{ "success": true, "data": ... }` on success or `
106
108
  - `gobi auth logout` — Log out of Gobi and remove stored credentials.
107
109
  - `gobi space list` — List spaces you are a member of.
108
110
  - `gobi space warp` — Select the active space. Pass a slug to warp directly, or omit for interactive selection.
109
- - `gobi session` — Session commands (get, list, reply).
110
- - `gobi session get` — Get a session and its messages (paginated).
111
- - `gobi session list` — List all sessions you are part of, sorted by most recent activity.
112
- - `gobi session create-reply` — Send a human reply to a session you are a member of.
113
111
  - `gobi update` — Update gobi-cli to the latest version.
114
112
 
115
113
  > Vault setup (`gobi vault init`) and file sync (`gobi vault sync`) live in the **gobi-vault** skill.
116
114
 
117
115
  ## Confirm before mutating
118
116
 
119
- `gobi session create-reply` posts a human-attributed message into a chat session — the message becomes part of the user's permanent chat history and triggers the agent to respond. Before running it, confirm with the user — show the exact session id and the message text. This applies even when running autonomously.
120
-
121
117
  `auth login` / `auth logout` are explicit user-driven commands; they prompt the user themselves and don't need an extra confirmation layer. `update` upgrades the CLI binary — fine to run without extra confirmation.
122
118
 
123
- Read-only commands (`auth status`, `session list`, `session get`, `space list`) run without confirmation.
119
+ Read-only commands (`auth status`, `space list`) run without confirmation.
124
120
 
125
121
  ## Reference Documentation
126
122
 
127
123
  - [gobi auth](references/auth.md)
128
- - [gobi session](references/session.md)
129
124
  - [gobi update](references/update.md)
130
125
  - [gobi space (list/warp)](references/space.md)
131
126
 
@@ -143,4 +138,5 @@ Read-only commands (`auth status`, `session list`, `session get`, `space list`)
143
138
  |----------|---------|-------------|
144
139
  | `GOBI_BASE_URL` | `https://api.joingobi.com` | API server URL |
145
140
  | `GOBI_WEBDRIVE_BASE_URL` | `https://webdrive.joingobi.com` | File storage URL |
141
+ | `GOBI_WEB_BASE_URL` | `https://gobispace.com` | Public web URL (used when assembling shareable links) |
146
142
  | `GOBI_SESSION_ID` | — | Default `--session` for `gobi draft add` (set automatically inside agent runs) |
@@ -11,19 +11,7 @@ Options:
11
11
 
12
12
  Commands:
13
13
  list List spaces you are a member of.
14
- get [options] [spaceSlug] Get details for a space. Pass a slug or omit to use the current space (from .gobi/settings.yaml or --space-slug).
15
14
  warp [spaceSlug] Select the active space. Pass a slug to warp directly, or omit for interactive selection.
16
- list-topics [options] List topics in a space, ordered by most recent content linkage.
17
- list-topic-posts [options] <topicSlug> List posts tagged with a topic in a space (cursor-paginated).
18
- feed [options] List the unified feed (posts and replies, newest first) in a space.
19
- get-post [options] <postId> Get a post with its ancestors and replies (paginated).
20
- list-posts [options] List posts in a space (paginated).
21
- create-post [options] Create a post in a space.
22
- edit-post [options] <postId> Edit a post you authored in a space.
23
- delete-post [options] <postId> Delete a post you authored in a space.
24
- create-reply [options] <postId> Create a reply to a post in a space.
25
- edit-reply [options] <replyId> Edit a reply you authored in a space.
26
- delete-reply [options] <replyId> Delete a reply you authored in a space.
27
15
  help [command] display help for command
28
16
  ```
29
17