Reference
CLI reference
sharedoc reaches the same workspace you see in the browser — projects, files, threads, channels, DMs, notifications, sync — from a terminal or an agent. 151 commands, each one call to the hub's API with the same rules as the web app. This page is built from the CLI's own command table, so it matches the version you install.
Install and log in#
curl -fsSL https://sharedoc.brightmotion.io/install.sh | sh
sharedoc login
sharedoc whoamiHeadless (CI, a container, an agent's own identity): skip login and set SHAREDOC_TOKEN to a token from Settings → CLI access, or one minted with sharedoc agents token. sharedoc update updates an installed CLI and restarts the sync service onto the new build.
Conventions#
- Shape.
sharedoc <noun> <verb> [args] [flags], flat. A project argument takes the slug or the display name in any case; a typo gets a did you mean. - Scope.
--workspaceand--projectchoose where a command acts. Inside a connected folder the folder decides; with one workspace or one project, that one. - JSON.
--jsonprints exactly one JSON document on stdout, errors included, and nothing else. Agents should always pass it. - Never a prompt. Destructive commands need
--yes. Where a command has--dry-runit checks permissions and previews the result without writing. - Attribution.
--as-agent claude-code --as-model opus-5marks a write as an agent's: Maya · via claude-code (opus-5). - Retries. Posting verbs take an
--idso a retry can't double-post;--if-versionmakes a write fail (exit 4) rather than overwrite someone else's change.
Errors#
Under --json an error is one object with a stable code, a message, and often a hint for the next command:
{
"error": {
"code": "not_found",
"message": "no project 'lumen-ap' you can open — did you mean 'lumen-app'?",
"hint": "sharedoc projects list --json"
}
}Exit codes#
| Code | Name | Meaning |
|---|---|---|
| 0 | ok | success |
| 1 | usage | bad arguments/flags |
| 2 | auth | not logged in, token revoked, or write scope required |
| 3 | not_found | workspace/project/file/thread not found |
| 4 | conflict | overlapping edits under --strict, or a stale --if-version (412) — nothing was written; re-read and retry |
| 5 | rate_limited | slow down; retry after the hinted seconds |
| 6 | server | server or network error |
| 7 | timeout | --wait ran out with the draft set still open — ask again later |
Global flags#
These work on every command.
--json | Print exactly one JSON document on stdout (errors too). Agents: always use this. |
--workspace value | Workspace slug/id/name to act in (default: the connected folder, else your only workspace) |
--project value | Project slug (default: the connected folder, else your only project in the workspace) |
--host value | Server base URL (default: $SHAREDOC_HTTP, else the host you logged in to) |
--as-agent value | Attribute writes to an agent, e.g. 'claude-code' (also $SHAREDOC_AGENT) |
--as-model value | The model behind --as-agent, e.g. 'opus-5' — shown as 'via claude-code (opus-5)' (also $SHAREDOC_MODEL) |
--limit n | Max rows for list commands (default 50, max 1000) |
--cursor value | Continue a list from a previous nextCursor |
--yes | Skip confirmation for destructive commands (agents are non-interactive) |
--dry-run | Show what would happen; write nothing |
--quiet | No footer / hints on stderr |
--allow-cwd-env | Keep SHAREDOC_* that bun loaded from the working directory's .env (the installed CLI never loads it) |
Environment and files#
| Name | What |
|---|---|
SHAREDOC_TOKEN | A CLI token to use instead of the saved login. Never read from a .env in the current folder, so a repo can't inject one; the same goes for every SHAREDOC_* variable here. Export them in your shell instead. |
SHAREDOC_HTTP | The server's base URL (default: the one you logged in to). |
SHAREDOC_AGENT · SHAREDOC_MODEL | Defaults for --as-agent and --as-model. |
SHAREDOC_TELEMETRY=0 · DO_NOT_TRACK=1 | Turn off the usage report the CLI sends after each command (the command's name, flag names without values, exit code, duration, version, OS). sharedoc telemetry off does the same for this machine. |
~/.config/share-doc/config.json | Saved logins, one per workspace, and the server they belong to (mode 0600). %APPDATA% on Windows; $XDG_CONFIG_HOME is honoured. |
~/.config/share-doc/sync.json | The sync set: every folder ⇄ project pair, and the chat mirror. Edit it with sync add / sync rm. |
~/.share-doc/ | The installed CLI bundle, which the sync service runs. |
Commands#
By area. writes needs a write-scope token.
Identity & scope
Sign in: opens the browser to authorize this device (AgentHog-style loopback + one-time code). With only a pre-browser credentials.json on the machine it migrates that token into config.json instead, no browser — asking which workspace it should act in (or --workspace).
--force | Re-login even if already logged in (revokes the stored tokens first) |
--no-browser | Print the URL and paste the code instead (implied over SSH) |
--no-wait | Print the URL to approve and exit — the first of two steps, for an agent that cannot answer a prompt: the human approves, the page shows a code, and --code finishes |
--code value | Finish a --no-wait login with the sd_code_… the authorize page showed (single-use, 5 minutes) |
--scope value | Token scope · one of read, write · default write |
--host value | Server to log in to (default: production) |
--workspace value | Migrating credentials.json: the workspace the token acts in by default (required under --json or without a terminal when it sees several) |
sharedoc login
sharedoc login --no-browser
sharedoc login --no-wait --json # an agent: send the human the url …
sharedoc login --code sd_code_… --json # … and redeem the code they paste back
sharedoc login --workspace brightmotion --json # migrate credentials.json headlessly
sharedoc-dev login --host http://localhost:3273Who and where am I: user, token, scope, workspaces, projects, server, credential source.
sharedoc whoami --jsonRevoke the stored tokens server-side and forget them locally.
List your CLI tokens (name, prefix, scope, last used).
sharedoc tokens revoke
writesRevoke one token by id.
<id> | token id from `tokens list` |
--yes | required |
Workspaces & projects
Workspaces you belong to, with your role.
Create a workspace, inbox and general channel. Requires an account-wide write token from Settings → CLI access.
<name> | display name |
--slug value | explicit stable slug (1–60 lowercase letters, numbers or hyphens) |
--if-not-exists | reuse --slug only when ownership, workspace and settings match; repair missing seed files |
Projects across saved logins, deduplicated and sorted by slug/id. Pages default to 50; continue with --cursor and the same filters.
--visibility value | private or workspace |
--query value | name or slug contains this text |
sharedoc projects list --workspace justin --jsonsharedoc projects create
writesCreate a project. It opens on a seeded sharedoc-instructions.md; the folder to sync comes next (sync add).
<name> | display name (the slug is derived) |
--slug value | explicit stable slug (1–60 lowercase letters, numbers or hyphens) |
--if-not-exists | reuse --slug only when ownership, workspace and settings match; repair missing seed files |
--workspace value | workspace slug — asked for on a terminal when you have several; required under --json then |
--private | members only (default: everyone in the workspace can open it) |
--no-channel | no chat channel for this project |
sharedoc projects create "Acme Diligence" --workspace brightmotion --jsonThe statuses a doc may carry (its front-matter `status`): the workspace's list, or with --project that project's effective list — its own, or the workspace's when it inherits (`inherited: true`). Each has a key (what the file holds), a label, one of nine colours and an optional description (when to set it).
--project value | a project's effective list (default: the workspace's) |
--field value | which property's list · default status |
sharedoc statuses list
sharedoc statuses list --project sharedoc --jsonsharedoc statuses add
writesAdd a status to the workspace's list (owner/admin) or, with --project, to that project's own list (project owner or workspace admin). A project that inherits gets its own list, starting from a copy of the workspace's.
<key> | lowercase letters, digits and dashes: ready-for-agent |
--label value | what chips show · default from the key: Ready for agent |
--color value | colour name · one of gray, red, orange, yellow, green, teal, blue, purple, pink · default gray |
--description value | when to set it — shown in the status picker |
--position n | where in the list (0 = first) · default last |
--project value | the project's own list instead of the workspace's |
--field value | which property's list · default status |
sharedoc statuses add ready-for-agent --color purple --description "fully specified; an agent may start"
sharedoc statuses add triage --color orange --project sharedocsharedoc statuses rm
writesRemove a status from a list. Docs that still say it are not rewritten: they show it as unknown (`invalid: ["unknown-status"]`), and the output says how many.
<key> | the status key |
--project value | the project's own list |
--field value | which property's list · default status |
sharedoc statuses rm triage --project sharedocsharedoc statuses mv
writesRename a status key (label kept unless --label). Docs are not rewritten: ones with the old key show it as unknown until edited.
<key> | the current key |
<new-key> | the new key |
--label value | a new label as well |
--project value | the project's own list |
--field value | which property's list · default status |
sharedoc statuses mv review ready-for-review --label "Ready for review"sharedoc statuses edit
writesChange a status's label, colour, description or position.
<key> | the status key |
--label value | what chips show |
--color value | colour name · one of gray, red, orange, yellow, green, teal, blue, purple, pink |
--description value | when to set it ("" clears it) |
--position n | move it (0 = first) |
--project value | the project's own list |
--field value | which property's list · default status |
sharedoc statuses edit blocked --color red --position 0Drop a project's own list so it uses the workspace's again.
--project value | the project (required) |
--field value | which property's list · default status |
sharedoc statuses inherit --project sharedocInspect IDs, access, counts and settings URL.
<slug> | stable slug |
sharedoc projects rename
writesRename the display name; IDs, slugs and links stay the same.
<slug> | stable slug |
<value> | new display name |
Change project access and reconcile its channel. --dry-run explains the access change.
<slug> | stable slug |
<value> | private or workspace |
sharedoc projects delete
writesDelete a project for good: its files (archived ones too), comments, channel, members, links and history. Posts elsewhere that only carry its label stay and lose the label; members' synced folders keep their local copies. Owners and workspace admins. Requires --yes; --dry-run says what would go.
<slug> | stable slug |
--yes | required |
--dry-run | preview what goes |
sharedoc projects delete old-experiment --dry-run
sharedoc projects delete old-experiment --yesDelete a workspace for good: every project and file in it, its channels, DMs and messages, its members' seats and invitations. Its agents are retired, its Slack connections disconnected, and CLI tokens that only opened it are revoked. People's synced folders keep their local copies. Only the owner. Requires --yes; --dry-run says what would go.
<slug> | stable slug |
--yes | required |
--dry-run | preview what goes |
sharedoc workspaces delete my-mistake --dry-run
sharedoc workspaces delete my-mistake --yesInspect IDs, access, counts and settings URL.
<slug> | stable slug |
Rename the display name; IDs, slugs and links stay the same.
<slug> | stable slug |
<value> | new display name |
sharedoc workspaces icon
writesSet the workspace's icon from a PNG, JPEG or WebP (up to 2 MB; the hub crops it to a centred square), or --remove it to go back to the initials square. Owners and admins. It shows in the sidebar's workspace picker and switcher, the settings header and the CLI login page; in the web app the same people get Add an icon under General in the workspace settings, with a crop to drag and zoom.
<slug> | stable slug |
[image] | the picture; omit with --remove |
--remove | clear the icon instead |
sharedoc workspaces icon acme ./logo.png
sharedoc workspaces icon acme --removePeople
Members of a workspace (or the explicit members of a project with --project), with each one's status. `kind` is `person` or `bot` (an agent identity).
The workspace's agents — bots an admin created so an agent can act as itself, each with a name, who controls it, whether it is paused, who may DM it, and (for admins and its owner) its tokens. --mine lists the ones you control, across workspaces.
--mine | the agents you control, in every workspace |
sharedoc agents list
sharedoc agents list --mine --jsonsharedoc agents create
writesCreate an agent (workspace owner/admin): a member of its own with the name given, controlled by you unless --owner names another member. It cannot invite, share, change settings or mint tokens; mint its first token with `agents token`. The name is how docs assign work to it (`assignee: Night shift`), so it may not contain '@' — and renaming it later leaves the docs that name it unassigned, with a warning, until someone picks again.
<name…> | its display name, e.g. "Night shift" — what a doc's assignee says; 1–60 characters, no @ |
--owner value | who controls it: an email, name or user id in the workspace · default you |
--dms value | who may DM it: owner (only whoever controls it) or workspace (anyone in it) · one of owner, workspace · default owner |
sharedoc agents create Night shift
sharedoc agents create "Night shift" --owner [email protected] --jsonsharedoc agents token
writesMint a write token for an agent, bound to its workspace — shown once; pass it to the agent as SHAREDOC_TOKEN. Its calls then write as the agent (add --as-agent / --as-model there for the 'via' chip). Admins and whoever controls it.
<agent> | its name or id (`agents list`) |
--name value | a label for the token · default <agent> token |
sharedoc agents token "Night shift" --name "cron on the server" --jsonsharedoc agents revoke
writesRevoke one of an agent's tokens. Admins and whoever controls it.
<agent> | its name or id |
<token-id> | from `agents list --json` (tokens[].id) |
--yes | required |
sharedoc agents revoke "Night shift" 6f1c… --yessharedoc agents pause
writesPause an agent: every call with its tokens is refused, by name, until `agents resume`. Its seat and tokens are kept. Admins and whoever controls it.
<agent> | its name or id |
sharedoc agents pause "Night shift"sharedoc agents resume
writesResume a paused agent.
<agent> | its name or id |
sharedoc agents resume "Night shift"sharedoc agents dms
writesChoose who may DM an agent: `owner` — only whoever controls it, the default — or `workspace`, anyone in it. Anyone else's message (or reply, or huddle) in a DM or group with it is refused by name and never reaches it — the web shows them an auto-reply instead — and their @-mentions, replies in threads it follows and doc comments post without notifying it. Another agent with the same controller always gets through. Admins and whoever controls it.
<agent> | its name or id |
<who> | owner or workspace |
sharedoc agents dms "Night shift" workspace
sharedoc agents dms "Night shift" owner --jsonsharedoc agents photo
writesSet an agent's profile photo from a PNG, JPEG or WebP (up to 2 MB; the hub crops it to a centred square), or --remove it to go back to the robot disc. Admins and whoever controls it. In the web app the same people get a camera button on its profile and its Agents row, with a crop to drag and zoom.
<agent> | its name or id |
[image] | the picture; omit with --remove |
--remove | clear the photo instead |
sharedoc agents photo "Night shift" ./owl.png
sharedoc agents photo "Night shift" --removesharedoc agents rm
writesDelete an agent (workspace owner/admin): its tokens are revoked and it leaves the workspace and its projects; what it wrote stays, signed "<name> (removed)".
<agent> | its name or id |
--yes | required |
sharedoc agents rm "Night shift" --yesShow your status: the emoji and text next to your name on every message and sidebar row.
sharedoc status
sharedoc status --jsonsharedoc status set
writesSet your status. It stays until you clear it, or clears itself after --for or at --until. --pause also snoozes your notifications for as long as it lasts.
[text…] | the status line, up to 100 characters (optional when --emoji is given) |
--emoji value | one emoji, or a :shortcode: like :calendar: (default 💬) |
--for value | clear after this long: 30m, 1h, 1h30m, 2d (1 minute to 7 days) |
--until value | clear at: eod (midnight tonight, your time zone), eow (midnight ending Friday), a date like 2026-09-28 (the start of that day, your time zone), or an ISO date-time with its offset |
--pause | also pause notifications until the status clears |
sharedoc status set "done for the day, started early" --emoji 🌅 --until eod --pause
sharedoc status set "in a meeting" --emoji :calendar: --for 1h
sharedoc status set "on vacation" --emoji 🌴 --until 2026-09-28sharedoc status clear
writesClear your status. If it paused your notifications, that snooze ends too (unless you changed the snooze since).
sharedoc status clearsharedoc members add
writesAdd people who are already in the workspace to a project (the way into a private one). Someone already on it keeps their role; someone not in the workspace is refused — invite them with `members invite`. Owners and editors may add.
<who…> | one or more emails, names or user ids (comma or space separated) |
--project value | project slug (default: the connected folder's) |
--role value | project role for the people added · one of viewer, commenter, editor · default editor |
sharedoc members add [email protected] [email protected] --project severance-plan --role commenter
sharedoc members add [email protected] --project severance-plan --dry-run --jsonsharedoc members invite
writesInvite people by email to the workspace, or to one project (--project, or the connected folder's). Nobody's existing role changes: results show the workspace and project role each person actually holds. A still-pending invitation comes back as `pending` and is not re-mailed — `invites resend <id>` does that.
<email…> | one or more emails (comma or space separated) |
--project-role value | with --project: what they may do there · one of viewer, commenter, editor · default editor |
--workspace-role value | the seat someone new gets in the workspace. guest = only the projects they are put on (the default with --project; member without). member needs you to be a member; admin, a workspace owner/admin · one of guest, member, admin · default guest with --project, else member |
--role value | old spelling of --workspace-role · one of guest, member, admin |
--project value | also put them on this project (someone already on it keeps their role) |
--dry-run | say what would happen to each address; writes and mails nothing |
sharedoc members invite [email protected] --project acme --project-role commenter --workspace-role guest
sharedoc members invite [email protected] --project acme --dry-run --jsonsharedoc members role
writesChange an explicit member's role on a project (--project; the project owner, or a workspace owner/admin who can open it — a private project only its members can) or in the workspace (--workspace; owners/admins). The owner's role never changes; nobody is added.
<who> | email, name or user id |
<role> | project: viewer|commenter|editor · workspace: guest|member|admin |
--project value | a project role |
--workspace value | a workspace role (instead of --project) |
--dry-run | show before → after; change nothing |
sharedoc members role [email protected] viewer --project severance-plan
sharedoc members role [email protected] guest --workspace acme --dry-runsharedoc members remove
writesTake someone's explicit membership off a project (--project), or remove them from the workspace and every project in it (--workspace). If they can still open the project through the workspace, the result says so. The owner cannot be removed. Requires --yes.
<who> | email, name or user id |
--project value | off this project |
--workspace value | out of this workspace (instead of --project) |
--yes | required |
--dry-run | preview, including access they keep |
sharedoc members remove [email protected] --project severance-plan --yesPending email invitations — a project's (--project) or the workspace's — with the id `invites resend|revoke` take. (`invite links` lists share links.)
--project value | project slug (default: the connected folder's) |
--workspace value | every pending invitation in the workspace you can see |
sharedoc invites list --project acmesharedoc invites resend
writesMail a pending invitation again — at most once every 10 minutes and 5 times in all. Whoever sent it, the project owner, or a workspace owner/admin who can open the project. The invitation stays as it was; `delivery` says whether the mail went.
<id> | invitation id from `invites list` |
--project value | the project it is for (an id from another project is not found) |
--dry-run | say whether it could be sent now |
sharedoc invites revoke
writesWithdraw a pending invitation so it no longer lets anyone in. Removes nobody — use `members remove`. Requires --yes.
<id> | invitation id from `invites list` |
--project value | the project it is for |
--yes | required |
--dry-run | preview |
sharedoc invite link
writesMint a join link for a project: anyone who opens it joins with the given role (a share link, /join/<token>).
--project value | project slug (default: the connected folder's) |
--role value | what the link grants · one of editor, commenter, viewer · default editor |
--expires value | 7d, 24h, 30d, never · default 7d |
--label value | a note for the settings page ("for the auditors") |
--file value | v0.40: share ONE file instead of the project — a scoped link that grants only that file (default role viewer, never expires) |
--folder value | v0.40: share one folder and everything inside it (default role viewer, never expires) |
--audience value | with --file/--folder: anyone (signed in) or workspace (current members only) · one of anyone, workspace · default anyone |
sharedoc invite link --project acme --role viewer --expires 30d
sharedoc invite link --folder clients/acme --role commenter --project dealsList a project's join links, revoked ones included. With --file/--folder: that path's scoped link (metadata only — secrets never appear in listings; `invite copy` returns it).
--project value | project slug (default: the connected folder's) |
--file value | the file whose link to show |
--folder value | the folder whose link to show |
--latest | with --file/--folder: the active link only (the default) |
sharedoc invite revoke
writesRevoke a join link; anyone who already joined stays. With --file/--folder: set that path to Restricted (people who joined through its link lose that access; direct grants and memberships stay).
[id] | link id from `invite links` (project links) |
--project value | project slug (default: the connected folder's) |
--file value | the file to restrict |
--folder value | the folder to restrict |
Re-copy a file/folder's active link (the same secret, nothing rotated). Managers only; Restricted returns the ordinary URL.
--file value | the file |
--folder value | the folder |
--project value | project slug (default: the connected folder's) |
sharedoc invite replace
writesRotate a file/folder's link: the old one stops working for everyone who joined through it, a new one is minted with the same settings. Requires --yes; --dry-run lists who loses access.
--file value | the file |
--folder value | the folder |
--project value | project slug |
--yes | required |
--dry-run | preview |
Who can open one file or folder and why: your own effective role; for a project owner or workspace admin also the direct grants, inherited folder grants, pending invitations and the link state.
<path> | project-relative path (a file with an extension, else a folder; or --file/--folder) |
--project value | project slug (default: the connected folder's) |
--file value | treat as a file |
--folder value | treat as a folder |
sharedoc access list clients/acme --project deals
sharedoc access list clients/acme/brief.md --jsonsharedoc access set
writesGive a person (an existing account) viewer, commenter or editor access to one file or folder. Adds to their membership access, never lowers it.
<path> | file or folder |
<email> | their account email |
--role value | what they may do · one of viewer, commenter, editor · default viewer |
--project value | project slug |
--dry-run | preview |
sharedoc access remove
writesTake a direct grant away (by email or grant id). Reports the access they still have through a parent folder or membership. Requires --yes.
<path> | file or folder |
<who> | email or grant id |
--project value | project slug |
--yes | required |
--dry-run | preview |
sharedoc access invite
writesInvite an email to one file or folder: an existing account is granted at once; anyone else gets a pending invitation (7 days) they redeem with that verified email. No email is sent unless --notify.
<path> | file or folder |
<email> | who |
--role value | what they may do · one of viewer, commenter, editor · default viewer |
--notify | send the invitation email |
--project value | project slug |
--dry-run | preview |
Files
Files in a project (any project you can open — no connected folder needed).
[project] | project slug or name (any case), or `_inbox` for this workspace's inbox (or --project) |
[path] | folder prefix |
--kind value | filter · one of markdown, blob |
--since value | only files changed since (24h, 7d, ISO) |
--depth n | one folder level instead of the whole tree — adds folders[] · default unlimited |
--status value | only markdown docs with this status (repeat, or comma-separate, for any of them) |
--assignee value | only docs assigned to them: me, an email, or an agent's name |
--unassigned | only markdown docs nobody is assigned to |
sharedoc files list homa-legal
sharedoc files list homa-legal --depth 1 --json
sharedoc files list _inbox --since 1h --json
sharedoc files list sharedoc --status blocked --assignee mePrint a file: markdown as text (latest revision), blobs as raw bytes. --thumb gives the small version of a picture or a video poster; --out writes to a file.
<project> | project slug |
<path> | file path inside the project |
--version n | a specific revision (markdown only) |
--thumb | the 640px thumbnail (images) or poster (video) instead of the original — read this first |
--out value | write the bytes to this file instead of stdout |
--with-media | markdown only: after the text, list every image and media link resolved to a project path (same as `files links`) |
sharedoc files cat homa-legal contract-v3.md
sharedoc files cat homa-legal media/shot.png --thumb --out /tmp/shot.webp
sharedoc files cat _inbox 2026-09/ab12cd-scan.pdf > scan.pdfEvery image and link inside a markdown document, resolved to project paths — what to `files cat` next. Relative links are joined to the doc's folder; external URLs are listed as such.
<project> | project slug |
<path> | the document |
sharedoc files links homa-legal notes/plan.md --json
sharedoc files links homa-legal notes/plan.mdRevisions of a markdown file.
<project> | project slug |
<path> | file path |
sharedoc files put
writesWrite a file. Markdown is 3-way merged into the live doc against --base, never overwritten.
<project> | project slug or name, any case (or `<project>/<path>` as one argument) |
<path> | file path inside the project |
--from value | read the bytes from a local file, or - for stdin (default: stdin when piped) |
--message value | revision summary, shown in `files history` |
--base n | the version you read before editing — makes this a merge, not an overwrite |
--strict | refuse (409 → exit 4) instead of merging overlapping edits |
sharedoc files put homa-legal contract-v3.md --from ./contract.md --base 7 --message "counsel edits"
cat plan.md | sharedoc files put homa-legal notes/plan.md --json
sharedoc files put homa-legal assets/site.png --from ./site.pngsharedoc files status
writesSet a markdown doc's statuses — the `status` list in its YAML front-matter, edited in place (comments and other keys kept; the block is added when missing and removed when nothing is left). Keys you set or add must be in the project's statuses (`statuses list`); any key can be removed. Order: --set/--clear, then --remove, then --add. One revision, source `meta`.
<project> | project slug (or `<project>/<path>` as one argument) |
<path> | the .md doc |
--add value | add a status (repeat, or comma-separate) |
--remove value | remove a status (repeat, or comma-separate) |
--set value | replace the whole list (comma-separated) |
--clear | remove every status |
--if-version n | the version you read (files list --json): if the doc moved on, nothing is written — 412 → exit 4 |
--message value | revision summary (default: "status → …") |
--replace-unreadable | the block does not parse (409): replace it with a clean one |
sharedoc files status sharedoc issues/x.md --add ready-for-agent
sharedoc files status sharedoc issues/x.md --remove ready-for-agent --add in-progress --if-version 7 --json || echo "someone else claimed it"
sharedoc files status sharedoc issues/x.md --set done
sharedoc files status sharedoc issues/x.md --clearsharedoc files assign
writesSet (or clear) a markdown doc's assignee — the `assignee` line in its front-matter: a person's email, or an agent's name (`assignee: Night shift`). `me` is you, or the agent whose token this is; `none` clears it. They must be able to open the project; they get a notification unless it is you. An agent's name is matched whatever its case, and only an agent is matched by name — a person is named by email.
<project> | project slug (or `<project>/<path>` as one argument) |
<path> | the .md doc |
<who> | an email, an agent's name, `agent:<id>`, `me`, or `none` |
--if-version n | the version you read: 412 → exit 4 when the doc moved on |
--message value | revision summary (default: "assignee → …") |
sharedoc files assign sharedoc issues/x.md me
sharedoc files assign sharedoc issues/x.md [email protected]
sharedoc files assign sharedoc issues/x.md "Night shift"
sharedoc files assign sharedoc issues/x.md noneMarkdown docs across every project you can open in a workspace, found by their front-matter properties — the overnight runner's question ("what is ready for an agent?") in one call. Filters AND together; archived docs are left out unless asked. Newest change first; pages of 50 (--limit up to 500), `nextCursor` continues, --all follows every page. Someone who reaches a project only through a shared file sees just that file, and never who it is assigned to.
--status value | has this status (repeat, or comma-separate, for any of them) |
--assignee value | assigned to me, an email, an agent's name, or a user id (comma-separate for any of them) |
--project value | only these projects (repeat, or comma-separate) |
--unassigned | nobody is assigned |
--has-status | has at least one status |
--path value | path starts with this (e.g. issues/) |
--archived | archived docs only |
--include-archived | live and archived docs |
--sort value | updated (newest first) or path (by project, then path) · one of updated, path · default updated |
--all | follow nextCursor to the end and print one answer (stops at a page boundary past 10 000 docs; nextCursor continues) |
sharedoc docs list --status ready-for-agent --json
sharedoc docs list --assignee me --has-status
sharedoc docs list --status blocked --status in-progress --project sharedoc --project kid-learn
sharedoc docs list --status ready-for-agent --all --json | jq -c '.docs[]'The same list with any filter tree: `{ and|or: [...] }` groups (4 deep, 50 conditions) of `{ field, op, value }`. Fields: status (contains, in, isEmpty, notEmpty), assignee (eq, in, isEmpty, notEmpty; 'me', an email or an id), project (eq, in), archived (eq, in), path (eq, in, startsWith), updatedAt (gt, lt; ISO, or 24h / 7d / 3m ago — m is months). A filter that never names archived matches live docs only; naming it anywhere (even in one or-branch) turns that off for the whole filter. Unsupported fields or ops are refused with the reason (exit 1).
--filter value | the filter tree as JSON |
--filter-file value | read the filter tree from a file, or - for stdin |
--sort value | keys, comma-separated, - for descending: -updatedAt (default), path, project, assignee — or a JSON list of { field, direction, nulls } |
--fields value | only these row keys (comma-separated; id always comes back) |
--all | follow nextCursor to the end (stops at a page boundary past 10 000 docs; nextCursor continues) |
sharedoc docs query --filter '{"and":[{"field":"status","op":"contains","value":"blocked"},{"field":"assignee","op":"eq","value":"me"}]}' --json
sharedoc docs query --filter '{"or":[{"field":"status","op":"isEmpty"},{"field":"assignee","op":"isEmpty"}]}' --sort project,path
sharedoc docs query --filter '{"field":"updatedAt","op":"gt","value":"7d"}' --fields path,statuses --all --jsonsharedoc files mv
writesMove or rename a file (its revisions, threads and comments follow it).
<project> | project slug |
<from> | current path |
<to> | new path |
--to-project value | move it into another project as well |
sharedoc files mv homa-legal draft.md contracts/v3.md
sharedoc files mv homa-legal scan.pdf scan.pdf --to-project homa-archivesharedoc files archive
writesArchive a doc — "closed", like an issue: off the tree and search, still readable at its URL with its comments and history; `files reopen` brings it back. Editing it from anywhere reopens it too. Requires --yes.
<project> | project slug |
<path> | file path |
--yes | required — the CLI never prompts |
sharedoc files archive homa-legal old-draft.md --yessharedoc files reopen
writesReopen an archived doc in place (history, comments and URL intact).
<project> | project slug |
<path> | file path |
sharedoc files reopen homa-legal old-draft.mdsharedoc files rm
writesAlias of `files archive` (kept for scripts). Requires --yes.
<project> | project slug |
<path> | file path |
--yes | required — the CLI never prompts |
sharedoc files rm homa-legal old-draft.md --yessharedoc files restore
writesAlias of `files reopen`.
<project> | project slug |
<path> | file path |
sharedoc files restore homa-legal old-draft.mdUnified diff between two revisions (default: the previous one → the latest).
<project> | project slug |
<path> | file path |
--from n | older version (from `files history`) |
--to n | newer version |
sharedoc files diff homa-legal contract-v3.md
sharedoc files diff homa-legal contract-v3.md --from 5 --to 7 --jsonA short-lived signed download URL for a blob (share it, curl it, feed it to a tool).
<project> | project slug |
<path> | file path |
--ttl n | seconds the URL stays valid · default 900 |
sharedoc files url _inbox 2026-09/ab12cd-scan.pdf --ttl 900 --jsonThreads and messages that reference a file ("discussed in n threads").
[project] | project slug (or --project) |
<path> | file path inside the project |
sharedoc files backlinks homa-legal contract-v3.md
sharedoc files backlinks homa-legal contract-v3.md --jsonThreads (doc comments)
Threads you can see: one doc with --doc, one project, or everything (open by default).
[project] | project slug (or --project; omit for every project) |
--doc value | only threads anchored to this doc, as <project>/<path> or a path with --project |
--status value | which threads · one of open, resolved, all · default open |
--mine | only threads you started, replied to, or are mentioned in |
--unread | only threads with messages you have not read |
sharedoc threads list --doc homa-legal/contract-v3.md --json
sharedoc threads list --status all --mineOne thread: anchor, status, followers, every message, and the references they carry.
<id> | thread id from `threads list` |
sharedoc thread show 2b7df1a0-… --json
sharedoc thread show 2b7df1a0-…sharedoc thread create
writesStart a doc-anchored thread (this is what a comment is). Quote the text you mean.
--doc value | the doc to anchor to, as <project>/<path> (or a path with --project) |
--quote value | exact text from the doc to anchor to |
--lines value | line range instead of a quote, e.g. 12-20 |
--body value | markdown body (§8 tags: @name, [[project/path.md#L1-L9]], [[thread:id]]) |
--body-file value | read the body from a file, or - for stdin |
--attach value | file(s) to upload to _inbox and tag in the body, comma-separated: photo.jpg,clip.mp4 |
--id value | client-generated uuid so a retry cannot double-post (else one is generated and printed) |
--channel value | post into a channel instead of a doc (`general`, `#general`, a project slug, or an id) |
--project value | with --channel: label the post with the project it is about (`none` for no label) |
sharedoc thread create --doc homa-legal/contract-v3.md --quote "the parties agree" --body "Is this the signed wording? @Emily" --json
sharedoc thread create --doc homa-legal/contract-v3.md --lines 12-20 --body-file review.mdsharedoc thread reply
writesReply in an existing thread — prefer this over opening a new one.
<id> | thread id |
--body value | markdown body (or --body-file / stdin) |
--body-file value | read the body from a file, or - for stdin |
--attach value | file(s) to upload to _inbox and tag in the body, comma-separated: photo.jpg,clip.mp4 |
--id value | client-generated uuid for the new message (idempotent retries) |
--draft | save it in the human's composer, unsent (it becomes a set of one if they have text there) |
--variant value | propose a version instead of posting — repeat for each; the human picks one |
--variants-file value | versions as a JSON array [{ "label", "body" }] from a file, or - for stdin |
--note value | with versions: what you read and how they differ |
--at value | schedule it instead: ISO, 'tomorrow 9:00', 'mon 9:00' (this machine's zone) |
--in value | schedule it this far ahead: 90m, 2h, 1d |
--notify | with a draft or versions: also notify the human (push) |
sharedoc thread reply 2b7df1a0-… --body "Agreed — see [[homa-legal/appendix-b.md#L4-L9]]" --json
cat notes.md | sharedoc thread reply 2b7df1a0-…sharedoc thread relabel
writesChange which project one of your own channel posts or DMs says it is about (or `none` to clear it). Moves the label only — not the post.
<id> | thread id |
<project> | project slug, or `none` |
sharedoc thread relabel 2b7df1a0-… sharedoc
sharedoc thread relabel 2b7df1a0-… nonesharedoc thread resolve
writesMark a thread resolved (only when you were asked to — resolving hides it).
<id> | thread id |
sharedoc thread resolve 2b7df1a0-…sharedoc thread reopen
writesReopen a resolved thread.
<id> | thread id |
sharedoc thread reopen 2b7df1a0-…sharedoc thread follow
writesFollow a thread (you are followed in automatically when you post or are mentioned).
<id> | thread id |
sharedoc thread follow 2b7df1a0-…sharedoc thread unfollow
writesStop following a thread.
<id> | thread id |
sharedoc thread unfollow 2b7df1a0-…sharedoc thread edit
writesRewrite one of your own messages (references are re-derived).
<message-id> | message id from `thread show` |
--body value | the new markdown body (or --body-file / stdin) |
--body-file value | read the body from a file, or - for stdin |
sharedoc thread edit 9c01a8b2-… --body "Fixed: @Emily-Ross owns this"sharedoc thread delete
writesTombstone one of your own messages. Requires --yes.
<message-id> | message id from `thread show` |
--yes | required — the CLI never prompts |
sharedoc thread delete 9c01a8b2-… --yessharedoc react
writesAdd (or with --remove, take back) an emoji reaction on a message.
<message-id> | message id from `thread show` |
<emoji> | a single emoji, e.g. 👍 |
--remove | remove your reaction instead of adding it |
sharedoc react 9c01a8b2-… 👍
sharedoc react 9c01a8b2-… 👍 --remove --jsonChannels & DMs
Channels and DMs you can see, with unread posts and mention counts.
--archived | archived channels instead |
sharedoc channels list
sharedoc channels list --jsonAudio huddles in the channels and DMs you can see, newest first: who started it, how long, who joined. Joining one needs a browser.
--live | only huddles going on right now |
sharedoc huddles list
sharedoc huddles list --live --jsonStart a huddle in a channel or DM — posts the announcement and notifies as usual; joining the call needs a browser.
<channel> | channel name or conversation id |
sharedoc channels create
writesCreate a channel (public by default). A project made with its channel toggle on already has #<slug>; --project gives one to a project that has none.
[name] | channel name (lowercase, dashes); defaults to the project slug with --project |
--project value | attach the channel to a project (its members can see it) |
--private | members only |
--topic value | one line shown in the header |
--members value | comma-separated emails/names to add |
sharedoc channels create launch --topic 'Sept launch' --members [email protected]sharedoc channels add
writesAdd workspace members to a channel you are in — the only way into a private one. A project's channel follows its project: use `members add --project` there.
<name> | channel name |
<who…> | one or more emails, names or user ids (comma or space separated) |
sharedoc channels add plans [email protected] [email protected]sharedoc channels join
writesJoin a public channel. You are in #general already, and in a project's channel when it has one — a project can be made without one, in which case its posts are labels on #general.
<name> | channel name |
sharedoc channels leave
writesLeave a channel.
<name> | channel name |
Archive a channel (hidden for everyone; posts stay). Requires --yes.
<name> | channel name |
--yes | required |
sharedoc channels delete
writesDelete a channel and every post in it — permanent, unlike archive. A project channel deleted this way stays gone. Requires --yes.
<name> | channel name |
--yes | required |
Invitations to shared channels sent to you, each with the workspaces you could connect it to. With a channel: as its host's owner or admin, who is invited and which workspaces are in it or waiting for their admin.
[channel] | a channel you host (omit for the invitations sent to you) |
sharedoc channel invites
sharedoc channel invites acme --jsonsharedoc channel accept
writesAccept an invitation to a shared channel into one of your workspaces (--workspace; one you are a member of, not a guest in). It is private there unless --open. As an owner or admin there it connects at once; otherwise it waits for one of them (`channel approve`).
<id> | invitation id from `channel invites` |
--name value | the channel's name in your workspace (default: the host's) |
--open | every member of your workspace can find and join it (default: only people added) |
sharedoc channel accept 3f1c… --workspace cockpit --name brightmotion
sharedoc channel accept 3f1c… --workspace cockpit --opensharedoc channel approve
writesAs an owner or admin of --workspace: let in a shared channel a member accepted (or --decline it). With no channel, list what is waiting.
[channel] | its name here, or its id |
--decline | turn it down instead |
sharedoc channel approve
sharedoc channel approve brightmotion --workspace cockpitEnd a shared channel for one workspace (owners and admins). Without --from: your workspace (--workspace) leaves a channel it joined. With --from: as the host, remove that workspace (its name or id, from `channel invites <channel>`). The side that goes loses the channel and its history, its own posts included; the host keeps everything, and a system post says who went. Requires --yes.
<channel> | channel name or id |
--from value | as the host: the workspace to remove |
--yes | required |
sharedoc channel disconnect brightmotion --workspace cockpit --yes
sharedoc channel disconnect acme --from Acme --yesRead a channel or DM: posts newest-last with reply counts; every id is a thread id (`thread show` / `thread reply`).
<name> | channel name, project slug, or conversation id (a DM id from `dm`) |
--since value | only posts since (24h, 7d, ISO) |
--project value | only posts labelled with this project |
--limit n | posts per page · default 30 |
--cursor value | continue from a previous nextCursor |
sharedoc channel history general
sharedoc channel history general --project sharedoc
sharedoc channel history homa-legal --since 24h --jsonsharedoc channel post
writesPost in a channel (the same as `thread create --channel`). Read the channel first.
<name> | channel name, project slug, or conversation id |
--body value | markdown body (§8 tags: @name, #channel, [[project/path.md]], [[thread:id]]) |
--body-file value | read the body from a file, or - for stdin |
--attach value | file(s) to upload to _inbox and tag in the body, comma-separated: photo.jpg,clip.mp4 |
--id value | client-generated uuid so a retry cannot double-post |
--project value | the project this post is about (a workspace-visible one) — optional but encouraged; defaults to the connected folder you are in, `none` opts out |
--draft | save it in the human's composer, unsent (it becomes a set of one if they have text there) |
--variant value | propose a version instead of posting — repeat for each; the human picks one |
--variants-file value | versions as a JSON array [{ "label", "body" }] from a file, or - for stdin |
--note value | with versions: what you read and how they differ |
--at value | schedule it instead: ISO, 'tomorrow 9:00', 'mon 9:00' (this machine's zone) |
--in value | schedule it this far ahead: 90m, 2h, 1d |
--notify | with a draft or versions: also notify the human (push) |
sharedoc channel post general --body 'Deployed v0.10 — notes in [[ops/deploys.md]]' --project sharedoc --as-agent claude-code --as-model opus-5
sharedoc channel post general --body 'The whiteboard from today' --attach ./whiteboard.jpgsharedoc dm
writesMessage one or more people directly (opens the DM once, reuses it after), or `me` for a note to self. Without a body: just open it and print its id. An agent takes DMs only from whoever controls it unless they set `agents dms <agent> workspace`; anyone else is refused with a 403 naming who it takes them from.
<user…> | email, display name, or user id — several for a group DM, `me` for a note to self |
--body value | markdown body (or --body-file / stdin) |
--body-file value | read the body from a file, or - for stdin |
--attach value | file(s) to upload to _inbox and tag in the body, comma-separated: photo.jpg,clip.mp4 |
--id value | client-generated uuid for the message |
--project value | the project this message is about — defaults to the connected folder you are in, `none` opts out |
--draft | save it in the human's composer, unsent (it becomes a set of one if they have text there) |
--variant value | propose a version instead of posting — repeat for each; the human picks one |
--variants-file value | versions as a JSON array [{ "label", "body" }] from a file, or - for stdin |
--note value | with versions: what you read and how they differ |
--at value | schedule it instead: ISO, 'tomorrow 9:00', 'mon 9:00' (this machine's zone) |
--in value | schedule it this far ahead: 90m, 2h, 1d |
--notify | with a draft or versions: also notify the human (push) |
sharedoc dm [email protected] --body 'Can you look at [[homa-legal/contract-v3.md]] today?'
sharedoc dm me --body 'the staging token is in 1Password'
sharedoc dm emily --jsonYour drafts, the variant sets waiting for you to choose, scheduled and failed messages. Private: nobody else sees any of it.
--drafts | only composer drafts |
--sets | only variant sets waiting to be chosen |
--scheduled | only scheduled messages |
--failed | only scheduled messages that could not be sent |
--resolved | sets settled in the last 30 days and what was chosen |
sharedoc drafts list
sharedoc drafts list --sets --json
sharedoc drafts list --resolvedsharedoc draft create
writesDraft a message for your human instead of posting it: one body goes into their composer (unless it has text in it), several become a set of versions they choose from. Nothing is sent.
[to…] | a channel (`general`, `#general`, an id), or @people for a DM / group — omit with --thread |
--thread value | a reply in this thread (channel or DM threads only) |
--body value | one body (or --body-file / stdin) |
--body-file value | read the body from a file, or - for stdin |
--variant value | one version — repeat for each (labelled A, B, C) |
--variants-file value | a JSON array [{ "label": "short", "body": "…" }, …] from a file, or - for stdin — use this for multi-line markdown |
--note value | with variants: what you read and how the versions differ |
--at value | schedule it: ISO time, 'tomorrow 9:00', 'mon 9:00' (this machine's zone). With variants: the time you suggest |
--in value | schedule it this far ahead: 90m, 2h, 1d |
--project value | the project a new post is about (as on `channel post`) |
--notify | also send the human a notification with push (for a long run they walked away from) |
--wait value | with variants: block until they choose (default 10m, 0 = no limit); exit 0 chosen · 4 dismissed · 7 still open |
--id value | client-generated uuid so a retry cannot create twice |
sharedoc draft create sharedoc --thread 2b7df1a0-… --variants-file - --note "Colin asked when the deploy lands; B commits to a date" < replies.json
sharedoc draft create general --body 'Deployed v0.30 — notes in [[ops/deploys.md]]'
sharedoc draft create @colin --body 'Can we move standup?' --at 'mon 9:00'One draft, scheduled message or variant (a set id works too).
<id> | draft or set id from `drafts list` |
sharedoc draft edit
writesChange a draft's text or a variant's label, schedule, reschedule or unschedule it.
<id> | draft id |
--body value | the new text (or --body-file) |
--body-file value | read the new text from a file, or - for stdin |
--label value | a variant's label |
--at value | schedule / reschedule |
--in value | schedule this far ahead |
--unschedule | back into the composer (refused if it has text in it) |
sharedoc draft edit 9c01a8b2-… --in 2h
sharedoc draft edit 9c01a8b2-… --unschedulesharedoc draft send
writesSend a draft or scheduled message now, as a post by you. For a person at a terminal — agents: never send for the human.
<id> | draft id |
sharedoc draft delete
writesThrow a draft away. Requires --yes.
<id> | draft id |
--yes | required |
A variant set: its versions, and — once the human has chosen — which one won and whether they edited it. --wait blocks until they decide.
<set-id> | set id from `draft create` or `drafts list --sets` |
--wait value | block until it is chosen or dismissed (default 10m, 0 = no limit); exit 0 chosen · 4 dismissed/failed · 7 still open |
sharedoc draft set show 51c0…
sharedoc draft set show 51c0… --wait 30m --jsonClose a variant set without sending anything. Requires --yes.
<set-id> | set id |
--yes | required |
Add a version to an open set (six at most). The human sees it appear.
<set-id> | set id |
--body value | the text (or --body-file / stdin) |
--body-file value | read it from a file, or - for stdin |
--label value | what makes this one different: short, formal, with the numbers |
Take a version out of its set (a set left empty is dismissed). Requires --yes.
<variant-id> | variant id |
--yes | required |
sharedoc draft pick
writesA person's choice from a terminal: put a version in the composer (the default), --send it, or schedule it with --at / --in. Agents: never pick for the human.
<variant-id> | variant id from `draft set show` |
--send | send it now, as it is |
--at value | schedule it |
--in value | schedule it this far ahead |
sharedoc slack connect
writesConnect a Slack workspace to your account: opens Settings → Slack's Add to Slack in your browser (it must be signed in to share-doc as you) and waits until Slack hands over access. Choose which conversations come in on that page. Running it again for a connected workspace reconnects it and keeps its links.
--workspace value | the share-doc workspace the Slack conversations go into (default: your first) |
--no-browser | print the page to open instead of opening it |
--timeout n | seconds to wait · default 300 |
--dry-run | print the page and stop |
sharedoc slack connect
sharedoc slack connect --workspace brightmotionYour Slack connections: the Slack workspace, your Slack handle, how many conversations are linked, status (ok; revoked: reconnect; disconnected), when the last event arrived. Never a token.
sharedoc slack list
sharedoc slack list --jsonsharedoc slack links
writesThe Slack conversations a connection brings in: name, read only or two-way, health, how far their history has come in, the Slack id and the share-doc conversation id. With --set <conversation> --direction: `both` makes it two-way (what you post goes to Slack as you), `in` read only, `off` removes the link (its conversation here is archived with its history; nothing changes in Slack). A conversation not linked yet is found in Slack by id or name and linked with --backfill days of history. Everything not named stays as it is.
[connection] | connection id or Slack workspace name (default: your only one) |
--set value | the conversation to change: Slack id (C…, G…, D…) or name (#design, Colin Wu) |
--direction value | with --set · one of in, both, off |
--backfill n | days of history for a link --set makes or brings back: 0, 7 or 30 · default 30 |
--all | include removed links |
--dry-run | say what --set would do |
sharedoc slack links
sharedoc slack links Brightmotion --json
sharedoc slack links --set "#design" --direction in
sharedoc slack links --set C0123ABCD --direction both --backfill 7How your Slack connections are doing: per connection its status, last event, last post, last error and switches; per linked conversation read only or two-way, health, how far its history has come in, its newest message and your Slack read cursor.
[connection] | connection id or Slack workspace name (default: all of them) |
sharedoc slack status
sharedoc slack status Brightmotion --jsonThe files on a message that came from Slack (they stay in Slack; the hub fetches them for you, with the same access as the message). Without --index: list them, numbered from 1, with a `gone` flag for one Slack no longer serves. With --index n: download file n to --out, or to its own name in the working directory (refused if that exists, unless --force). Message ids and their slackFiles are on `thread show --json`.
<message-id> | a message id from `thread show --json` |
--index n | download this file (1-based, as listed) |
--out value | write it here (overwrites); default: the file's name in the working directory |
--force | overwrite an existing file of that name in the working directory |
--dry-run | say where it would go; download nothing |
sharedoc slack file 5f0c…
sharedoc slack file 5f0c… --json
sharedoc slack file 5f0c… --index 1 --out /tmp/shot.pngPeople in a connected Slack workspace you can start a DM with (from share-doc's copy of its member list; bots and deactivated accounts left out). Matches the name, @handle or email; share-doc teammates are marked and listed first. Use a handle or the Slack id with `slack dm`.
[query] | part of a name, handle or email |
--team value | which Slack workspace (name or id), when you have more than one |
--limit n | at most this many · default 50 |
sharedoc slack people colin
sharedoc slack people --team Brightmotion --jsonsharedoc slack dm
writesStart a Slack DM (one person) or group DM (two to eight) from share-doc, as you, and bring it in as a private share-doc conversation; one that is already linked just opens, one you removed comes back with its history. Nothing is sent to Slack until you post in it (`channel post <conversation-id>`).
<person> | one or more: @handle, name, or Slack id (U…) — see `slack people` |
--team value | which Slack workspace (name or id), when you have more than one |
--dry-run | resolve the people and stop |
sharedoc slack dm @colin
sharedoc slack dm @colin @dana --jsonDisconnect a Slack workspace: Slack revokes the token and share-doc deletes it, and the conversations it brought in are archived with their history (their composers close). Connecting the same Slack account again lets you tick them back in. Nothing changes in Slack. Requires --yes; --dry-run lists what would be archived. --forget then removes a disconnected connection from your list (its archived conversations stay).
[connection] | connection id or Slack workspace name (default: your only one) |
--yes | required |
--forget | remove it from your list (disconnects it first if needed) |
--dry-run | list what would be archived |
sharedoc slack disconnect Brightmotion --dry-run
sharedoc slack disconnect Brightmotion --yesSearch & events
Full-text search over messages, doc comments and file contents, fuzzy over paths, folders, channels and people — everything you can open, shared folders included. `in:<project>` covers its docs, its channel, and any post labelled with it. Filters ride in the query: in:#channel|project|dm, from:me|email|name|agent, is:unread, is:archived (archived docs only; excluded otherwise), has:file, before:/after:2026-09-01|7d, and for files only status:<key> (repeat = any of them), assignee:me|email|name, is:unassigned, has:status (a search for other things with these says so in query.notes rather than widening). `--types` picks any combination (files,folders,messages,channels,people) and, with no query words, browses what is recent in scope; `--workspace all` searches every workspace you can see; `--cursor` continues one group.
[query] | words, "exact phrases", -exclusions, plus filters like in:#general from:me (optional with --types) |
--scope value | one group, or all (the older spelling; not with --types) · one of all, files, messages, threads, channels, people · default all |
--types value | comma list of content types: files, folders, messages, channels, people (default: all) |
--source value | messages from chat (channels, DMs) or document comments · one of all, chat, comments · default all |
--by-thread | group matching messages by thread (one row per thread, best match shown) |
--folder value | only under this folder of --project |
--conversation value | only this conversation (id) |
--in value | sugar for in: — #channel, a project slug, or dm |
--from value | sugar for from: — me, an email, a name, or agent |
--unread | sugar for is:unread |
--archived | sugar for is:archived — search archived docs instead of live ones |
--has-file | sugar for has:file (messages that tag a file) |
--after value | sugar for after: — 2026-09-01 or 7d |
--before value | sugar for before: |
sharedoc search 'contract deadline' --json
sharedoc search 'status:blocked assignee:me' --types files
sharedoc search 'deploy' --in '#general' --after 7d
sharedoc search 'invoice' --scope files
sharedoc search 'is:unread from:emily' --scope messages
sharedoc search 'sync' --types files,folders --workspace all
sharedoc search 'budget' --types messages --source comments --project sharedoc
sharedoc search --types files --project sharedoc --folder specs --limit 20The change log (who did what, when) from a cursor; --follow streams.
--cursor n | start after this event id (default: last 50) |
--kinds value | comma-separated kinds, e.g. doc.updated,member.added |
--follow | keep streaming (SSE); output becomes one event per line (NDJSON with --json) |
Your notifications (mentions, DMs, replies in threads you follow, new threads on docs you follow). Unread only by default.
--all | include what you have already read |
--kind value | one kind · one of mention, dm, reply, thread, channel, invite, system, reminder |
--watch | print what is unread, then keep streaming new ones (SSE) until Ctrl-C |
sharedoc unread
sharedoc unread --watch --jsonsharedoc unread read
writesMark notifications read by id.
<id…> | ids from `unread` |
sharedoc unread ack
writesMark everything read (needs --yes), or everything in one conversation / before a time.
--conversation value | only this channel / DM |
--before value | only notifications up to this ISO time |
--yes | required for a blanket ack |
sharedoc notify prefs
writesShow or change your notification preferences (spec §3.8): level, thread replies, doc follows, email timing, snooze, working hours.
--set value | key=value[,key=value] — keys: email browser pushAlways level threadReplies docFollows inboxDrops invites emailMode awayMinutes digestHour markRead snoozeUntil (ISO or null) hoursDays (every|weekdays) hoursStart hoursEnd (minutes from midnight) timezone (IANA) |
sharedoc notify prefs
sharedoc notify prefs --set level=all,emailMode=never
sharedoc notify prefs --set snoozeUntil=2026-09-04T17:00:00Z
sharedoc notify prefs --set hoursDays=weekdays,hoursStart=540,hoursEnd=1080Sync
sharedoc connect
writesTwo-way sync a local directory with a project (long-running by default).
<project> | project slug |
<dir> | local folder (empty folder = pulls everything). Dotfiles, node_modules, lockfiles, __pycache__/, build output at the top (dist/, build/, out/, target/, coverage/) and what the folder's .sharedocignore lists are never added; .gitignore is not read |
--once | reconcile once and exit — pull remote, push local, print a summary |
--reset | move the folder aside into .share-doc/backup-<ts>/ and re-seed from the hub (never deletes) |
--strict | overlapping edits are a conflict, not a merge: nothing is applied, --once exits 4 |
--no-comments | do not write <doc>.comments.md next to docs that have open threads (on by default; the sidecar is read-only and never pushed) |
--force | go ahead on a folder the sync set already covers, or on a git repository root (pair docs/ instead — a root pair uploads README and source) |
--yes | first sync of a folder past 50 files or 20 MB: skip the warning, and send it at once even in a workspace with large files turned off (which otherwise holds it for approval) |
--folder value | map the local folder to this folder inside the project instead of the whole project (a shared folder's recipient can connect just that folder) |
--sync-default value | what this connection syncs when no folder rule says otherwise (v0.40) · one of inherit, on, off · default inherit |
--dry-run | say what would be mapped: no registration, no scan, no transfer |
sharedoc connect homa-legal ~/deals/homa
sharedoc connect homa-legal ./homa --once --json
sharedoc connect homa-legal ./homa --once --strict # exit 4 on a conflict
sharedoc connect homa-legal ./homa --resetsharedoc sync add
writesAdd a folder ⇄ project pair, or channels to mirror, to this machine's sync set (~/.config/share-doc/sync.json).
[project] | project slug or name, any case (with <dir>) |
[dir] | local folder to keep in sync with it |
--strict | this pair: overlapping edits are a conflict, not a merge |
--folder value | map the folder to this folder inside the project (default: the whole project) |
--sync-default value | the connection's default: inherit (use folder defaults), on (all unless excluded), off (none until selected) · one of inherit, on, off · default inherit |
--force | pair a git repository root anyway (refused otherwise — pair its docs/ folder) |
--yes | first sync past 50 files or 20 MB: skip the warning, and send it at once even in a workspace with large files turned off (which otherwise holds it for approval) |
--channel value | mirror these channels, comma-separated: general,ops |
--channels | mirror every channel you can see (project channels included) |
--dms | mirror DMs and group DMs too (off unless asked) |
--dir value | root folder for the channel mirror · default ~/sharedoc/chat |
--history value | how far back to backfill: 30d, 12h, all · default 30d |
--workspace value | the workspace this pair or the mirror runs in — stored in sync.json; needed when the saved login is one token that sees several workspaces |
sharedoc sync add homa-legal ~/deals/homa
sharedoc sync add ops ~/ops --strict
sharedoc sync add --channel general,homa-legal
sharedoc sync add --channels --dms --dir ~/chat
sharedoc sync add --channels --workspace brightmotion # a login with no workspace on itsharedoc sync rm
writesRemove a folder pair (<dir>), one channel (#name) or the whole channel mirror (channels) from the set, and disconnect the pair's connection on the hub. Never touches files — local or on the server: the way out for a paired folder that went `missing` when you meant to stop syncing it.
<what> | <dir> | #channel | channels |
sharedoc sync rm ~/deals/homa
sharedoc sync rm #random
sharedoc sync rm channelsA paired folder is gone (`missing` in `sync status`) and you did mean to delete everything in it: archive on the server every file its connection syncs, as one batch (`sync undo` reopens it), then unpair it as `sync rm` does. The running sync never reads a vanished folder as deletes. Requires --yes; refuses a folder that is still there.
<dir> | the paired folder, as in `sync list` |
--yes | required |
--dry-run | list what it would archive |
sharedoc sync archive-missing ~/old-notes --dry-run
sharedoc sync archive-missing ~/old-notes --yesThe sync set as configured: pairs, channel rules, resolved paths.
The set as it is right now: per pair state/files/last push/pull/error, the channel mirror, whether `sync run` is up (and the service manager's view: launchd on macOS, systemd on Linux).
sharedoc sync run
writesTHE process: every pair and the channel mirror, live, until Ctrl-C (one lock per machine). --once reconciles everything and exits.
--once | reconcile every pair, backfill channels, print one table, exit (4 if a strict pair conflicted, 6 if a pair could not run) |
--strict | treat every pair as strict for this run |
--service | service mode: under launchd, timestamps and a log at ~/Library/Logs/sharedoc/sync.log (rotated at 5 MB); under systemd, plain lines to the journal |
sharedoc sync run
sharedoc sync run --once --jsonsharedoc sync install
writesRun `sync run` as a user service — launchd on macOS, systemd --user on Linux — that starts at login and is restarted if it dies. Idempotent. Waits (up to 20 s) for every pair and the channel mirror to report live or an error before printing; `settled: false` means check `sync status` in a moment.
sharedoc sync install
sharedoc sync statussharedoc sync uninstall
writesStop and remove the user service (launchd / systemd). The set and every folder stay.
Tail the service log: ~/Library/Logs/sharedoc/sync.log on macOS, the journal (journalctl --user -u sharedoc-sync) on Linux.
--follow | keep following, like tail -f |
--lines n | how many lines · default 200 |
--which value | macOS: sync (ours) or launchd (what launchd captured before the logger was up); the journal holds both on Linux · one of sync, launchd |
sharedoc sync logs
sharedoc sync logs --followThe hub's inventory of machine connections ("connections" in Settings): status, last seen vs last synced, whether settings are applied. Owners see their local paths; project managers a coarse row per machine. `sync list` is this machine's local set.
--project value | one project's connections (default: the connected folder's project, else every connection you own) |
--all | every connection you own across projects |
sharedoc sync endpoints --project homa-legal
sharedoc sync endpoints --all --jsonsharedoc sync pause
writesPause a connection: transfers stop, folder rules are kept, local edits wait. The running sync notices within 30 s.
[connection-id] | from `sync endpoints` (default: the connected folder's own connection) |
--dry-run | preview |
sharedoc sync approve
writesApprove what a connection is waiting on. --deletes: the files its folder deleted in bulk (more than 25 at once), held rather than archived on the server — this archives them. Otherwise, in a workspace with large files turned off (workspace settings → Storage; on, the default, nothing waits): its big first push (a `sync add` past 50 files or 20 MB without --yes), or with --file / --held the big files it holds over the workspace's ask-first size. Only on the person's say-so — `sync status` and the log say what is waiting.
[connection-id] | from `sync endpoints`, or the paired folder's path (default: the connected folder's own connection) |
--deletes | the bulk delete it is holding |
--file value | a held file's project path (repeatable) |
--held | every file it is holding |
--dry-run | preview |
sharedoc sync discard
writesKeep the files a connection's folder deleted in bulk and is holding: nothing is archived, and the folder pulls them back from the server. (Putting the files back does the same.)
[connection-id] | from `sync endpoints`, or the paired folder's path |
--deletes | required: the held deletes are what is discarded |
--dry-run | preview |
sharedoc sync undo
writesReopen every file one burst of a folder's deletes archived on the server, in one call — by default the newest burst with anything still archived (last 30 days). --list shows the bursts. The folder, if still paired, pulls them back.
[connection-id] | from `sync endpoints`, or the paired folder's path |
--batch value | which burst (from --list, or the log's "undo with" line) |
--list | the bursts, newest first |
--dry-run | list what it would reopen |
sharedoc sync undo 3f2a9c1e
sharedoc sync undo ~/kid-learn/docs --listsharedoc sync resume
writesResume a paused connection: it re-reads its settings and reconciles.
[connection-id] | from `sync endpoints` |
--dry-run | preview |
sharedoc sync disconnect
writesDisconnect a connection on the hub: its credential is revoked and any running sync stops; local files, cloud files and membership stay. Requires --yes. Reconnecting is a new `sync add` / `connect`.
[connection-id] | from `sync endpoints` |
--yes | required |
--dry-run | preview what is kept |
sharedoc sync folders
writesWhat one connection syncs, folder by folder: list the tree with each folder's rule, effective state and why; `set <path> --mode on|off|inherit` changes a rule (a narrower On beats an ancestor Off); `--default` sets the connection default; `--clear-children <path>` removes overrides under a folder.
[connection-id] | from `sync endpoints` (default: the connected folder's) |
[set <path>] | the folder to change (project-relative) |
--mode value | with `set`: on | off | inherit (inherit removes the rule) · one of on, off, inherit |
--default value | the connection default: inherit = use folder defaults · on = all folders unless excluded · off = no folders until selected · one of inherit, on, off |
--clear-children value | remove every explicit rule strictly under this folder |
--if-match value | config revision the change is based on (a stale revision is a conflict, exit 4) |
--dry-run | preview the impact (files, bytes) without saving |
sharedoc sync folders 1a2b3c4d
sharedoc sync folders 1a2b3c4d set media --mode off
sharedoc sync folders 1a2b3c4d set media/previews --mode on
sharedoc sync folders 1a2b3c4d --default off --dry-runA project's folder sync defaults (what connections that use folder defaults do with each folder, future folders included). Without --sync-default: list. The root is on|off; other folders may inherit.
[path] | project-relative folder ("" or omitted = the root) |
--project value | project slug (default: the connected folder's) |
--sync-default value | set this folder's default · one of on, off, inherit |
--dry-run | preview |
sharedoc folders settings --project homa-legal
sharedoc folders settings media --project homa-legal --sync-default offYour devices (one per ShareDoc installation) with their connections, grouped by machine.
sharedoc devices rename
writesRename a device's label; its identity and connections are unchanged.
<device-id> | from `devices list` |
<label> | new label |
Disconnect every connection a device holds for you (never erases its disk). Requires --yes; --dry-run lists the affected projects first.
<device-id> | from `devices list` |
--yes | required |
--dry-run | list what would be disconnected |
Self-description
This help. --json dumps the full command table for agents.
--json | machine-readable |
The live data contract: entities, fields, enums, and the command table.
[entity] | one entity, e.g. events, documents, tokens |
Print the CLI version.
Turn usage reporting on or off, or show whether it is on. After each command the CLI tells the server it is logged in to the command's name, the names of the flags given (never their values or any arguments), the exit code, the duration, the CLI version, OS and architecture. Nothing about files, paths, projects or messages. Also off with SHAREDOC_TELEMETRY=0 or DO_NOT_TRACK=1.
[on|off] | turn it on or off; omit to show the current state |
sharedoc telemetry
sharedoc telemetry off
SHAREDOC_TELEMETRY=0 sharedoc files list acmesharedoc update
writesUpdate this CLI in place: runs the installer from the server it targets, then restarts the sync service.
--no-restart | leave the sync service (launchd / systemd) running the old bundle |
sharedoc update
sharedoc update --dry-run