// 00 — Reference
CLI reference
wspc is the command-line surface for the wspc workspace. This page gives the stable setup path and common examples. For live command and option truth, run wspc --help and wspc <command> --help.
Examples below use wspc. If not installed globally, prefix with npx.
// 01 — Global options
Global options
Live global flags:
| Option | Effect |
|---|---|
--version | Print the installed CLI version and exit. |
--json | Output raw JSON when the command supports machine-readable output. |
--account <email> | Run as a specific signed-in account instead of the active account. |
--help | Show help for a command. |
Output format. Commands render a human-readable layout when stdout is an
interactive terminal, and emit raw JSON when it is not — piped, redirected, or
captured by a tool/agent. So scripts and AI agents get a parseable shape without
opting in. Force either mode explicitly with --json or the WSPC_OUTPUT
environment variable (WSPC_OUTPUT=json / WSPC_OUTPUT=pretty); the explicit
setting wins over terminal detection.
Use wspc --help and wspc <command> --help before relying on a flag not shown here.
// 02 — Auth and environments
Auth and config
wspc is a shared surface for agents and humans. This section answers two questions: who am I, and which deployment am I talking to. Sign in with OAuth or provide an existing WSPC API Key, then switch the active environment between production, local dev, and custom deploys without rewriting config.
wspc login # Start OAuth device-flow login for production.
wspc login --api-key wspc_xxx # Store an existing API key.
wspc login --api-base http://127.0.0.1:8787 --env dev
# Log in against a non-production API base and store it under the dev env.
wspc whoami # Show the active env, account, and organization.
wspc logout # Remove the active account from the current env.
wspc login uses OAuth device flow by default. --api-key is an alternative for an existing WSPC API Key. --api-base targets a non-production API base, and --env chooses the local config env name used to store those credentials.
wspc config show # List configured envs with tokens redacted.
wspc config use prod # Switch current_env.
wspc config use dev # Switch to a previously stored dev env.
wspc config set actor codex # Set a field on the active account.
Run wspc config --help for the current config fields and command shape.
Multiple accounts per env
One env can hold several signed-in accounts. Running wspc login again does not overwrite the existing account — it appends the newly authenticated account to the current env and makes it active. List the accounts in the current env, then switch which one commands run as.
wspc account ls # List accounts in the current env (active marked with ✓).
wspc account switch alice@wspc.app # Set the active account for the current env.
account ls prints a table keyed by email (EMAIL, USER, ACTOR, AUTH); the active account is marked with ✓. account switch <email> sets the active account and fails if that email is not signed in to the current env — run wspc account ls or wspc login first.
To run a single command as a non-active account without switching, use the global --account <email> flag.
wspc --account alice@wspc.app whoami # Run one command as a specific account.
The account a command runs as resolves from --account <email>, then the env’s active account, then the sole account if exactly one exists. A --account value that names an account not signed in to the current env is an error. With no override and multiple accounts but no active one set, the command errors and asks you to pass --account <email> or run wspc account switch <email>.
// 03 — API keys
API keys
One key per agent or device. Revoke individually without disturbing the rest. The full key string surfaces exactly once at creation — store it then, or revoke and reissue. Maximum 25 active keys per user. The web console at app.wspc.ai/settings/api-keys mirrors these commands.
wspc keys ls # List your active API keys (label, last4, created, last used).
wspc keys create --label "Claude Desktop" # Create a new key; full value printed once.
wspc keys edit key_01HXX..ABCD --label "New Label" # Edit an active key's label.
wspc keys rm key_01HXX..ABCD # Soft-revoke a key by id.
Revocation is a soft delete. The key stops authenticating immediately; the row stays for audit.
Org invites and members
Invite an email to your Workspace, list and revoke invites, accept or decline invites addressed to you, and manage Workspace Members.
Invite creation and acceptance can return WORKSPACE_MEMBER_LIMIT_REACHED. Pending invites do not count toward capacity. Remove a Workspace Member or upgrade to Startup or Business, then retry the same invite.
wspc org invite invite bob@example.com # create an invite (sends email)
wspc org invites # list invites issued by your org
wspc org invite revoke <invite-id> # revoke a pending invite
wspc invites # list invites addressed to you
wspc invite accept <invite-id> # accept (switches your org)
wspc invite reject <invite-id> # decline
wspc org members # list members of your organization
Accepting switches your organization; data scoped to your previous org is no longer visible. Member removal is available through the MCP/HTTP API, not the CLI.
// 04 — Todo
Todo
Todo is the shared task store for agents and humans. Hierarchy through parent / child. State flows open → in_progress → done or cancelled. Delete is soft. Restore brings it back. Hand the agent a backlog and let it triage — mistakes are recoverable.
wspc todo add "Submit expenses" --project prj_01HW3K # Create a todo in a project (required).
wspc todo add "Book hotel" --project prj_01HW3K --description "Use refundable rate"
# Create a todo with details.
wspc todo add "Draft outline" --project prj_01HW3K --parent-id <todo-id> # Create a child todo.
wspc todo add "File taxes" --project prj_01HW3K --due-at 2026-05-31 # Create a todo with a due date.
wspc todo add "Investigate outage" --project prj_01HW3K --status in_progress
# Create a todo that starts outside the default open state.
wspc todo ls --project prj_01HW3K # List active todos in a project (required).
wspc todo ls --project prj_01HW3K --status in_progress # Filter by status.
wspc todo ls --project prj_01HW3K --user-id usr_01HW3K # List todos assigned to a user in a project.
wspc todo ls --project prj_01HW3K --due-before 2026-05-20 # List todos due before 2026-05-20 (exclusive).
wspc todo ls --project prj_01HW3K --due-after 2026-05-13 # List todos due on or after 2026-05-13.
wspc todo ls --project prj_01HW3K --due-after 2026-05-13 --due-before 2026-05-20
# List todos due in a window — useful for "what's due this week".
wspc todo ls --project prj_01HW3K --include-deleted
# Include soft-deleted todos.
wspc todo show <id> # Show one todo by id.
wspc todo update <id> --title "Submit reimbursable expenses"
# Rename a todo.
wspc todo update <id> --status in_progress # Move a todo into in-progress state.
wspc todo update <id> --due-at 2026-06-01 # Reschedule a todo's due date.
wspc todo update <id> --due-at "" # Clear a todo's due date.
wspc todo update <id> --description "" # Clear a todo description.
wspc todo done <id> # Mark a todo as done.
wspc todo rm <id> # Soft-delete one todo.
wspc todo rm <id> --cascade # Soft-delete a todo and its descendants.
wspc todo restore <id> # Restore a soft-deleted todo.
wspc todo restore <id> --cascade # Restore a soft-deleted todo and its descendants.
--description accepts Markdown (CommonMark + GFM tables / strikethrough / task lists), stored verbatim server-side, rendered client-side. todo update --description "" clears the description. Omitting the flag leaves it unchanged. Re-parent with todo update --parent-id <id>.
--due-at accepts YYYY-MM-DD. todo update --due-at "" clears the due date. Omitting --due-at leaves it unchanged. For queries, --due-after is an inclusive lower bound, --due-before is an exclusive upper bound. Use either, or both for a window. Due filters currently exclude todos with no due date set.
--status accepts open, in_progress, done, or cancelled. --project <id> (or -p <id>) is strictly required for listing todos via todo ls and creating todos via todo add. todo ls --user-id filters by assignee user id.
Delete is soft. todo ls hides soft-deleted todos by default — pass --include-deleted to include them. todo show hides a soft-deleted todo unless you pass --include-deleted true.
todo add, todo ls, todo show, todo update, and todo done accept --json.
Recurring todo rules
Weekly review, monthly reconciliation, anything cyclical. A rule pairs an RFC 5545 RRULE with a template todo. The system materializes future instances on a rolling horizon, so each cycle gets its own completable row instead of one reopened-forever task. Edits to a rule affect only future materializations — already-materialized history stays put.
wspc todo rule add "Weekly review" \
--rrule "FREQ=WEEKLY;BYDAY=MO" \
--dtstart 2026-05-18 \
--project prj_01HW3K
# Create a weekly recurring todo rule and materialize upcoming instances.
wspc todo rule add "Pay rent" \
--rrule "FREQ=MONTHLY;BYMONTHDAY=1" \
--dtstart 2026-06-01 \
--project prj_01HW3K \
--type typ_01HW3K \
--description "Send transfer confirmation" \
--parent-id <todo-id>
# Create a rule under a specific todo type, with template metadata.
wspc todo rule ls --project prj_01HW3K # List active recurring rules (shows each rule's type).
wspc todo rule show <rule-id> # Show a rule, its type, and its template snapshot.
wspc todo rule rm <rule-id> # Soft-delete a recurring rule.
wspc todo rule rm <rule-id> --expected-version 3 # Delete only if the rule is still version 3.
--rrule accepts an RFC 5545 RRULE pattern — exclude DTSTART and TZID. --dtstart is the first materialization date in YYYY-MM-DD. --project is the required project ID under which the rule and its materialized instances reside; this option is strictly required for both rule add and rule ls commands. The rule keeps a template todo and materializes future instances from it. --description and --parent-id set the template fields used for future materializations.
--type is optional. Omit it to adopt the project’s default todo type. When set, it must be an active type in the rule’s project; the type’s custom-field defaults are copied onto the template and every materialized instance. If the type has a required field with no default, rule add fails with MISSING_REQUIRED_FIELD — set a default on the type, or pick a different type, before creating the rule.
Materialization horizon: 14 days forward. The system creates one independent todo per RRULE occurrence inside that window — each has its own id, status, and due_at, lives in todo ls, and completes or deletes on its own. Subsequent triggers or edits top up the next 14 days. Creating or editing a rule materializes within the window immediately.
Subtasks on every occurrence. A rule keeps a hidden template todo. To make a checklist appear on every occurrence, attach the subtasks to the template — not to one day’s instance. Get the template id from wspc todo rule show <rule-id> (the template.id field), then create children under it:
wspc todo rule show tdr_01HW3K # Copy the template.id (tod_xxx) from the output.
wspc todo add "Write notes" --parent-id tod_xxx --project prj_01HW3K
wspc todo add "Post summary" --parent-id tod_xxx --project prj_01HW3K
# Future occurrences re-materialize so each one carries both subtasks.
Subtasks are one level deep, and only future (unmodified) occurrences pick them up — already-materialized days you have edited stay as they were.
rule rm accepts an optional --expected-version optimistic lock. Omit it to use the server’s current version. Pass it only when you need “fail if version has moved”.
rule add、rule ls 與 rule show 支援 --json。
建立時可用 --assignee-user-id <user-id> 指定目前 Workspace Member;省略時使用 rule creator。每次產生的 Root Todo 與 Child Todo 都指派給這位 assignee。Rule 建立後不能修改 assignee,也沒有修改 assignee 的 CLI option。
wspc todo rule add "Weekly review" --rrule "FREQ=WEEKLY" --dtstart 2026-09-15 --project prj_xxx --assignee-user-id usr_xxx
wspc todo rule ls --project-id prj_xxx
wspc todo rule show tdr_xxx --json
rule ls 與 rule show 的 pretty/JSON 輸出包含 creator user_id、assignee_user_id 與 assignee_status。狀態為 valid、not_member 或 unknown;後兩者會暫停產生或重建 occurrences,保留既有 Todos。Membership 恢復後從目前 rolling window 繼續,不回補過去日期。--user-id 仍依 creator 篩選。
指定非成員時回傳 INVALID_ASSIGNEE(HTTP 422);無法驗證 membership 時回傳 ASSIGNEE_CHECK_UNAVAILABLE(HTTP 503),CLI 以非零 exit code 結束且不建立 rule。
Custom types
Types group todos under a label and optionally declare custom field schemas. Every project starts with a Default type; create more when you need per-project workflows (e.g., a Bug type that requires a severity custom field). Types are project-scoped — a type belongs to exactly one project, and assigning a todo to it requires both to live under the same project.
The CLI exposes types as read-only — list them with wspc todo type ls. Creating, editing, and deleting types is done through the MCP/HTTP API.
wspc todo type ls --project-id prj_01HW3K # List active types in a project (required).
wspc todo type ls --project-id prj_01HW3K --user-id usr_01HW3K # Filter by creator.
wspc todo type ls --project-id prj_01HW3K --include-deleted true # Include soft-deleted types.
--project-id is strictly required on type ls. To create or modify a type — including hide_core_fields and custom_fields schemas — use the MCP todo_type_* tools or the HTTP API. todo type ls accepts --json.
Comments
Threaded comments on individual todos. Author is the authenticated user. Delete is soft — deleted comments are hidden from default lists with no restore path.
wspc todo comment add <todo-id> "Great progress on this."
# Add a comment to a todo.
wspc todo comment ls <todo-id> # List comments on a todo (oldest-first by default).
wspc todo comment ls <todo-id> --order desc # List comments newest-first.
wspc todo comment ls <todo-id> --include-deleted # Include soft-deleted comments.
wspc todo comment edit <comment-id> "Updated wording." # Edit a comment's content.
wspc todo comment rm <comment-id> # Soft-delete a comment.
todo comment add takes the target todo id and the comment content as positional arguments. Content maximum is 10 000 characters. --order accepts asc (default) or desc. --include-deleted shows soft-deleted comments. There is no restore for comments; once deleted they are gone from the default list permanently.
todo comment ls accepts --json.
// 05 — Projects
Projects
Projects group related todos and define a default todo type for new work. They are organization-scoped, soft-delete safe, and useful when an agent needs to separate unrelated backlogs without switching accounts.
Project commands live under todo (wspc todo project …), and the CLI exposes
create, list, and soft-delete. Showing, renaming, re-typing, and restoring
projects is done through the MCP/HTTP API.
wspc todo project ls # List active projects.
wspc todo project add "Launch plan" # Create a project.
wspc todo project add "Bugs" --default-todo-type-id typ_01HW3K
# Create a project with an explicit default todo type.
wspc todo project rm prj_01HW3K # Archive the project and active user-visible todos. Keep recurrence templates.
todo project add takes the project name as a positional argument.
--default-todo-type-id sets the project’s default todo type. todo project rm
takes the project id as a positional argument and soft-deletes the project,
cascading to the todos under it; restore is available through the MCP/HTTP API.
todo project ls accepts --json.
// 06 — Calendar
Calendar
event ls --q 以 literal substring 搜尋 title、description、location,支援長字串與 UTF-8。ASCII 比對不分大小寫;%、_ 是一般字元,不是 wildcard。
私人 ICS 訂閱網址可從 Web 的 Settings → Calendar 或 MCP calendar_create_subscription 取得,並使用 get/reset/disable 管理。CLI 尚無獨立 subscription command。取得 URL 的人可讀取目前帳號及 Workspace 的所有活動內容,請保持私密。Google Calendar 使用 From URL 訂閱;一般 ICS download/import 是一次性副本,更新頻率由外部 app 決定。
Imported Event 的 JSON 會包含 invitation.uid 與外部 invitation.organizer;Agenda single item 也會保留。這些活動由外部 Organizer 管理,event set 回 IMPORTED_EVENT_READ_ONLY。event rm/event restore 仍可使用,但不寄 attendee 通知;隱藏期間收到的外部更新會保留,restore 才重新顯示。ICS 使用外部 UID 與修訂。此版收件同步預設停用,啟用須待 provider 驗證完成。
Received Email detail 的 optional calendar_sync 表示該封通知的處理結果,包含 status、固定 reason 與具備 Calendar read 權限時才回傳的 event_id。一般原信與停用期間收件不會有同步結果;刪除原信不會取消活動。
The calendar lets the agent book meetings, reschedule, and dispatch invites on your behalf. Time fields accept ISO 8601 and natural language ("tomorrow 12:30pm", "next Monday 9am"). All-day events, attendees, optimistic lock via --expected-version, and standard .ics export are first-class. Cancelled and soft-delete are distinct: cancelled stays in the lifecycle for notification; rm removes the event from default lists entirely.
wspc event add "Lunch with Alice" \
--start "tomorrow 12:30pm" \
--end "tomorrow 1:30pm" \
--location "Taipei HQ" \
--attendee "Alice <alice@example.com>"
# Create an event from natural-language times and add an attendee.
wspc event add "Team offsite" --start 2026-05-10 --end 2026-05-11 --all-day
# Create a one-day all-day event.
wspc event add "Office days" --all-day --start 2026-08-17 --end 2026-08-18 --rrule "FREQ=WEEKLY;BYDAY=MO,WE"
# Create an all-day recurring series.
wspc event add "UTC sync" --start 2026-08-17T09:00:00Z --end 2026-08-17T10:00:00Z --rrule "FREQ=WEEKLY;BYDAY=MO"
# Create a UTC timed recurring series.
wspc event add "New York office hours" --start "2026-08-17 9am" --end "2026-08-17 10am" --rrule "FREQ=WEEKLY;BYDAY=MO" --tz America/New_York
# Create a local recurring series that stays at 09:00 across DST.
wspc event add "Release review" --start 2026-05-15T09:00:00+08:00 --end 2026-05-15T10:00:00+08:00
# Create an event from exact ISO times.
wspc event add "Tentative sync" --start "next Monday 9am" --end "next Monday 9:30am" --status tentative
# Create a tentative event.
wspc event ls # List upcoming events.
wspc event ls --include-past # Include events that have already ended.
wspc event ls --include-deleted # Include soft-deleted events.
wspc event ls --deleted-only # List past and future Calendar Trash.
wspc event ls --from "next Monday" --to "next Friday"
# List events in a date range.
wspc event ls --q "Alice" --limit 20 --cursor <cursor>
# Search and continue a paginated list.
wspc event occurrences <event-id> --from 2026-06-01 --to 2026-07-01
# Expand one all-day recurring series in a bounded half-open window.
wspc event occurrences <event-id> --from "next Monday" --to "next month" --tz America/New_York --limit 100
# Expand a timed series; --tz only parses the query boundaries.
wspc event agenda --from "this Monday" --to "next Monday" --tz Asia/Taipei
# Merge overlapping single events and recurring occurrences in one bounded agenda.
wspc event occurrence set <series-id> <recurrence-id> --start "tomorrow 10am" --end "tomorrow 11am"
# Reschedule one occurrence; its recurrence id remains unchanged.
wspc event occurrence cancel <series-id> <recurrence-id>
# Cancel only one occurrence.
wspc event occurrence restore <series-id> <recurrence-id>
# Remove the exception and inherit the original series time/status again.
wspc event show <event-id> # Show one event with details.
wspc event show <event-id> --include-deleted true --tz Asia/Taipei
# Show a soft-deleted event and display times in a chosen timezone.
wspc event set <event-id> --start "tomorrow 1pm" --end "tomorrow 2pm"
# Reschedule an event.
wspc event set <event-id> --all-day --start 2026-05-10 --end 2026-05-11
# Reschedule an all-day event with an exclusive end.
wspc event set <event-id> --start "next Monday 9am" --end "next Monday 10am" --tz Asia/Taipei
# Parse natural-language times in a chosen timezone.
wspc event set <event-id> --title "Planning sync" --location "" --url ""
# Rename an event and clear optional text fields.
wspc event set <event-id> --attendee "Alice <alice@example.com>" --attendee bob@example.com
# Replace the attendee list.
wspc event set <event-id> --description "" # Clear the event description.
wspc event set <event-id> --rrule "" # Convert a series master to a one-time event.
wspc event set <event-id> --tz "" # Keep the instants and return a local series to UTC.
wspc event set <event-id> --status cancelled # Mark the event cancelled but keep the record.
wspc event set <event-id> --status confirmed --expected-version 4
# Update only if the event is still version 4.
wspc event rm <event-id> # Soft-delete an event from default lists.
wspc event rm <event-id> --expected-version 4 # Delete only if the event is still version 4.
wspc event restore <event-id> # Restore a soft-deleted event.
wspc event ics <event-id> > event.ics # Save the event as an iCalendar file.
Time fields accept ISO 8601 or natural language. Natural-language parsing resolves the timezone in this order: --tz <IANA>, WSPC_TZ, system timezone. Example: --tz Asia/Taipei.
--all-day means --start and --end are YYYY-MM-DD, and --end is the first date outside the event. --start 2026-05-10 --end 2026-05-11 --all-day covers one full day. --start 2026-05-10 --end 2026-05-13 --all-day covers three full days, 5/10 through 5/12.
This Exclusive End input applies to @wspc/cli v0.7 and later. During the v0.6-to-v0.7 release window, v0.6 still treats the CLI input end as inclusive: use --start 2026-05-10 --end 2026-05-10 for one day or --start 2026-05-10 --end 2026-05-12 for three days. After upgrading to v0.7+, move each all-day mutation end forward by one day: use --end 2026-05-11 for one day or --end 2026-05-13 for three days.
--rrule accepts an RFC 5545 RRULE value such as FREQ=WEEKLY;BYDAY=MO,WE; omit the RRULE: prefix. The server validates and returns a canonical rule. All-day series use date-only start/end and DATE UNTIL. Timed series without an explicit --tz are sent as UTC; WSPC_TZ and the system timezone remain parsing-only defaults. When a non-empty --tz is explicitly combined with recurrence, the CLI sends offset-bearing timestamps plus canonicalizable time_zone, so wall-clock time stays fixed across DST; timed UNTIL remains UTC. On event set, omit --rrule to leave the rule unchanged, pass --rrule "" to clear recurrence and its zone, or pass --tz "" to preserve the instants while returning the series to UTC semantics. Update, cancel, delete, and restore affect the whole series. event ls returns one persisted series master and does not expand occurrences.
event occurrences expands exactly one recurring series without creating Event rows. --from and --to are required and select occurrence starts in the half-open window [from, to); use date-only boundaries for all-day series and offset-bearing date-times for timed series. Windows are limited to 366 days. --limit defaults to 100 and accepts 1–200; pass the opaque --cursor to continue. Its --tz only parses natural-language boundaries and never changes or persists the series time zone.
event agenda combines overlapping single Events and recurring Occurrences without returning Series Masters. --from and --to are required; --tz resolves from the explicit flag, WSPC_TZ, or the system zone and is always sent as the Agenda View Time Zone. A window may span at most 31 local days. Cancelled items are hidden unless --include-cancelled is set; --limit accepts 1–200 and --cursor continues a stable page. If the candidate set changes while paging, restart after VERSION_CONFLICT; if the bounded expansion budget is exceeded, narrow the window.
event occurrence set|cancel|restore mutates exactly one Recurrence ID. set requires complete --start and --end, reads the Series Master first, and parses human time as all-day, UTC, or the canonical Series Time Zone. Optional --tz is only a parse hint and must match the series zone. --expected-version refers to the Exception Version, not the Series Master version. event occurrences --include-cancelled exposes cancelled exceptions; table output always includes RECURRENCE_ID, START, END, STATUS, EXCEPTION_VERSION, and TIME_ZONE.
event set --status cancelled differs from event rm. Cancelled events stay in the calendar lifecycle. rm is soft-delete — default lists hide it. Use wspc event restore <event-id> to bring a soft-deleted event back.
--expected-version is an optional optimistic lock. Omit to use the server’s current version. Pass when you need to pin the version you last read.
--description accepts Markdown (CommonMark + GFM tables / strikethrough / task lists). Stored verbatim server-side, rendered client-side. Invitation emails carry the raw Markdown text — most email clients show it as plain text.
event add 與 event set 支援 --description、--location、--url、--status、--all-day、--rrule 與 --tz。--attendee 可重複使用,set 會取代整份 attendee 清單。event ls 支援 --q、--limit、--cursor、--include-deleted、--deleted-only、--include-past 與 --tz。event show 支援 --include-deleted 與 --tz。event ics 將 ICS 文字寫到 stdout,可用 > event.ics 儲存。
event ls --deleted-only 只列目前 user/Workspace 的 Calendar Trash,包含過去與未來 Event,優先於 --include-deleted 及 --include-past;明確時間 bounds 與 --q 仍套用。分頁依 start ASC, id ASC 排序,restore 後應從第一頁重新查詢。
event add, event ls, event occurrences, event agenda, event occurrence set|cancel|restore, event show, and event set accept --json.
// 07 — Drive
Drive
Drive libraries keep files in the shared Workspace. Use the remote commands to manage libraries and inspect stored files. Use the local commands to bind a folder on your computer and keep it in sync with one library.
Export the Workspace
wspc --account example@example.com drive export add
wspc --account example@example.com --json drive export show
wspc --account example@example.com drive export download exp_01HW3K4N9V5G6Z8C2Q7B1Y0M3F --output ./drive-export.tar
add returns immediately with an Export Job; an existing unfinished job is returned with reused: true. If the creation response is lost, the outcome is unknown: run show before retrying. show reports the Account, Workspace, status, file and byte counts, expiry, and error code; a Workspace with no job returns job: null. Downloads use the specified job ID even after a newer export starts.
Packages are uncompressed tar archives of current files in active Libraries, excluding version history and Trash. They do not count against Workspace Storage, and a full quota does not block export. Each package expires seven days after completion. Export is not a point-in-time snapshot: batches observe current versions as they run. Pause writes and create a fresh job when a stable copy is required. New jobs fail if a selected source is missing; packages created before this guarantee was deployed cannot be certified retroactively, so create a new export.
The output directory must already exist on a filesystem supporting hard links. The CLI writes to a private temporary file, checks the exact package identity and length, then publishes without overwriting any existing file or symlink, including a target created during download. There is no overwrite or copy fallback. Failed downloads do not emit a success result; cleanup failures report the remaining temporary path on stderr. A server without the identity and length headers must be upgraded; the CLI does not fall back to downloading latest.
Libraries
wspc drive library add "Research" # Create a Drive library.
wspc drive library ls # List active libraries.
wspc drive library ls --include-deleted true # Include soft-deleted libraries.
wspc drive library show <library-id> # Show one active library.
wspc drive library update <library-id> --name "Notes" # Rename a library.
wspc drive library update <library-id> --name "Notes" --expected-version 2
# Rename only if the library is still version 2.
wspc drive library rm <library-id> # Soft-delete an empty library.
library ls supports --limit and --cursor for pagination. library update and library rm accept --expected-version as an optional optimistic lock. A library must be empty before library rm can delete it.
檔案與搜尋
wspc drive manifest get <library-id> # List active file entries.
wspc drive manifest get <library-id> --path-prefix research/ --limit 50
# List one folder prefix and limit the page size.
wspc drive manifest get <library-id> --cursor <cursor> # Continue a paginated manifest.
wspc drive search <library-id> --query "launch plan" --limit 20
# Search indexed text files.
wspc drive file history <library-id> --path research/plan.md
# List the current active file versions, newest first.
manifest get 回傳檔案 metadata,支援 --include-deleted true、--deleted-only true 與 --since-cursor <cursor>。drive search 搜尋已索引的文字檔案。file rm 建立 tombstone,既有版本依 Workspace retention policy 保留。
History 的檔案身分
drive file history <library-id> --path <path> 查詢該 path 當下的 active File entry。已發布 CLI 0.10.0 尚無 History --entry-id,因此不能鎖定先前選取的檔案。Missing/deleted-only path 回 404 NOT_FOUND;同 path 的 tombstones 不會混入版本清單。
HTTP GET /drive/libraries/{id}/files/history?path=...&entry_id=... 與 MCP drive_file_history 可帶選取時的 entry_id。不符時回 409 VERSION_CONFLICT,不得省略 ID 重試。成功回 path、entry_id、entry_version、current_version_id 與 newest-first versions,metadata 與 versions 來自同一 snapshot。History read 不構成未來 restore 授權;mutation 仍須遵守自己的確認契約。
安全 move/delete(HTTP)
Move/rename 與 soft-delete 要求原確認的 entry_id、來源 path 與 expected_entry_version(大於等於 1 的 safe integer)。只有 path/版本不足以識別檔案:另一份檔案可以移入同一路徑且恰有相同版本。
最低相容 CLI 為 0.10.0。CLI 0.9.0 及更早版本的 file rm/sync delete 缺完整 identity,會收到 400;請先升級。0.10.0 的 rm/sync delete/move adapter 已通過 released package 對 candidate 的驗收;啟用前仍須確認 live OpenAPI required fields。舊 sync state 缺 entry ID 時必須停止舊刪除意圖、重新同步並確認,不得 fresh lookup 後直接刪除或標記同步成功。
以下 HTTP 範例只使用已確認的原值:
curl -X POST "https://api.wspc.ai/drive/libraries/$LIBRARY_ID/files/move" \
-H "Authorization: Bearer $WSPC_API_KEY" \
-H "Content-Type: application/json" \
-d '{"entry_id":"<confirmed-entry-id>","from_path":"research/plan.md","to_path":"archive/plan.md","expected_entry_version":3}'
curl -X POST "https://api.wspc.ai/drive/libraries/$LIBRARY_ID/files/delete" \
-H "Authorization: Bearer $WSPC_API_KEY" \
-H "Content-Type: application/json" \
-d '{"entry_id":"<confirmed-entry-id>","path":"research/plan.md","expected_entry_version":3}'
兩個範例是獨立操作,成功 move 後不能繼續使用舊 path/版本刪除。Move 回 moved,delete 回 deleted;僅重新確認同一已刪 entry 的目前版本才回 unchanged,舊 active 版本重送仍回 409 VERSION_CONFLICT。缺 confirmation 回 400 VALIDATION_ERROR;Library 不可見回 404 NOT_FOUND;purge claim 回 409 PURGE_IN_PROGRESS;目的 path 已占用回 409 PATH_CONFLICT。Conflict 後重新檢視並確認,禁止自動取最新 identity/版本重送。Timeout 時先按 identity 讀回;無法判定就保留 unknown,不猜測成功或 rollback。
安全歷史還原(HTTP)
Historical restore 現在要求確認時的 entry_id、path、expected_entry_version 與選定的 version_id。CLI 0.8.0/0.9.0 的 drive file restore 尚缺前兩個確認 flags,因此此舊 command 暫不可用;CLI 的相容實作與 release 由外部 repository 接續。後續先用 installed help 確認 --entry-id 與 --expected-entry-version,並確認 live OpenAPI 已將這兩個欄位列為 required,才啟用該 flow。
以下 HTTP 範例使用使用者已確認的值;不得在 conflict 後自動讀最新 Entry Version 重送。expected_entry_version 必須是大於等於 1 的 safe integer。409 VERSION_CONFLICT 表示確認已過期,需重新檢視並取得新的確認;錯誤 source 回 404 FILE_NOT_FOUND,purge claim 回 409 PURGE_IN_PROGRESS。成功回 updated 或 unchanged,不回 created。同 bytes 仍檢查 identity、Entry Version 與 source,但不變更 metadata 或 history。
curl -X POST "https://api.wspc.ai/drive/libraries/$LIBRARY_ID/files/restore" \
-H "Authorization: Bearer $WSPC_API_KEY" \
-H "Content-Type: application/json" \
-d '{"entry_id":"<confirmed-entry-id>","path":"research/plan.md","expected_entry_version":3,"version_id":"<selected-version-id>"}'
保存回傳的 x-cb-drive 並在後續 request 帶回。若 timeout 或 response 遺失,結果可能已提交,先讀回 entry identity、Entry Version、current version 與 hash 判斷,不得改用 blind restore。
搜尋續頁(HTTP)
HTTP search 回傳 { results, next_cursor? };有 next_cursor 才能 Load more,末頁與空頁省略該欄位。以 installed wspc drive search --help 確認 CLI 是否已提供 --cursor;外部 CLI 尚未發佈該 flag 時,使用以下 HTTP example。limit 預設 20、最多 50,整數夾至 1–50,無效或非整數回預設,空字串夾至 1;續頁可改 page size。
Example 沿用呼叫端的 apiBase、libraryId、bearerToken、原始 query 與 driveBookmark。Search Cursor 與 x-cb-drive 分別保存,token 都只原樣傳回。以 loadMore() 進行首查及續頁,canLoadMore 為 false 時停止。不要同時呼叫多次 loadMore()。
let results = [];
let cursor;
let canLoadMore = true;
async function loadMore(limit = 20) {
if (!canLoadMore) return;
const params = new URLSearchParams({ query, limit: String(limit) });
if (cursor !== undefined) params.set("cursor", cursor);
const headers = { Authorization: `Bearer ${bearerToken}` };
if (driveBookmark) headers["x-cb-drive"] = driveBookmark;
const response = await fetch(
`${apiBase}/drive/libraries/${encodeURIComponent(libraryId)}/search?${params}`,
{ headers },
);
const body = await response.json();
if (!response.ok) {
const code = body.error?.code;
if ([401, 404].includes(response.status) || code === "VALIDATION_ERROR") {
canLoadMore = false;
}
throw new Error(code ?? `HTTP ${response.status}`);
}
results = [...results, ...body.results];
cursor = body.next_cursor;
canLoadMore = cursor !== undefined;
driveBookmark = response.headers.get("x-cb-drive") ?? driveBookmark;
}
網路或暫時性錯誤保留已顯示結果與原 cursor,由使用者重試;成功才追加結果。VALIDATION_ERROR 提示重新搜尋:清空 results/cursor、將 canLoadMore 設為 true,再呼叫 loadMore()。401/404 停止載入並交回登入或權限處理,不無限 retry。變更 query/library/Workspace 時也必須重設搜尋狀態。
結果依 relevance,再依內部 file ID 排序。整張 FTS5 索引未變時,連續翻頁不重不漏;任何 library 的索引變動都可能造成重複或遺漏,重試也不保證同一 response。Cursor 無 TTL,anchor 刪除或時間經過不使其失效;這不是 snapshot 或完整匯出。path 可改名,不是穩定 identity,client 去重也無法補回遺漏。
Local folder sync
wspc drive bind ./Research --library <library-id> # Bind a local folder to a library.
wspc drive sync once ./Research # Run one sync pass.
wspc drive watch ./Research # Watch the folder and keep syncing.
wspc drive watch ./Research --debug # Also write local debug events.
The path defaults to the current directory. drive bind connects the folder to an existing Drive library. drive sync once performs one two-way sync pass and exits. drive watch keeps running until stopped; --debug appends NDJSON events to <folder>/.wspc-drive/debug.log.
Drive list, show, search, manifest, history, restore, and mutation commands support the global --json output mode.
// 08 — Email
Email gives you @wspc.app addresses for sending and receiving — the agent’s outward identity. Common pattern: spin up a dedicated alias for one stream (subscription, form, notification) and let the agent read, classify, reply, or pipe attachments downstream. One account, many aliases — for example mailme1@wspc.app, bills1@wspc.app, newsletter1@wspc.app. Deleting an alias stops new mail. Historical mail stays readable.
Aliases
Aliases are a top-level command group (wspc alias …).
wspc alias add mailme1@wspc.app # Create a receiving alias.
wspc alias add mailme1@wspc.app --json # Print the created alias as JSON.
wspc alias ls # List active aliases.
wspc alias ls --include-deleted # Include soft-deleted aliases.
wspc alias rm mailme1@wspc.app # Soft-delete an alias so it stops receiving mail.
wspc alias restore mailme1@wspc.app # Restore a soft-deleted alias.
Alias identifier 是完整 email address,可使用 Platform Email Domain @wspc.app 或同 organization 已完整 verified 且 enabled 的 Custom Email Domain。Platform Email Domain 的 local part 維持 5–32 字元;Custom Email Domain 接受 1–64 字元,例如 me@example.com。兩者皆以英數開頭,僅允許英數、點、底線與連字號,並轉成 lowercase;reserved words 只限制 Platform Email Domain。平台地址依 Current Workspace tier 計算容量:Free 3、Personal 10、Startup 40、Business 200。同一上限也適用於 Workspace 在 rolling 30-day window 內新建立的平台地址數量;刪除只釋放 active capacity,不會重設建立額度。額度耗盡時回 ALIAS_CREATION_LIMIT_EXCEEDED,CLI 使用的 HTTP response 包含 Retry-After;restore 不算新建立。Custom-domain aliases 不使用此 rolling budget,維持每位使用者最多 10 個 active aliases。Domain 未註冊於目前 organization 時回 ALIAS_DOMAIN_NOT_FOUND;verification 尚未完整或 domain 受限時回 ALIAS_DOMAIN_NOT_READY。Billing 失敗時回 EMAIL_ENTITLEMENTS_UNAVAILABLE,不建立或還原地址。CLI 不接受舊 alias id 或 local-part selector。刪除後停止收取新信、釋放容量並保留歷史郵件;使用 wspc alias restore <email> 在目前容量內還原。
Custom domains
wspc domain add example.com # Register a domain and print required DNS records.
wspc domain ls # List registered domains for your organization.
wspc domain show example.com # Show domain status and DNS records.
wspc domain verify example.com # Ask the provider to verify current DNS records.
wspc domain rm example.com # Delete a domain when no active aliases use it.
Custom-domain registration is available to Startup and Business Workspaces, with at most one unverified candidate at a time. Free and Personal cannot register custom domains. Verification does not itself enable mail use: the domain must also fit the effective included or paid capacity. Entitlement loss restricts excess domains without deleting retained data.
These commands register an organization domain and manage DNS setup / verification. Organization domains can be used for custom-domain aliases only after status, sending_status, and receiving_status are all verified and the effective entitlement enables the domain. domain rm soft-deletes the domain after the upstream provider delete succeeds. It returns DOMAIN_IN_USE when active aliases still use the domain, and deleted domains are hidden from active list/show/verify/delete commands.
Inbox
wspc email ls # List recent emails.
wspc email ls --unread-only true # List only unread emails.
wspc email ls --since 1747000000000 --limit 50 # Up to 50 emails since a Unix-ms timestamp.
wspc email ls --alias-email mailme1@wspc.app # Filter by full alias address.
wspc email ls --cursor <cursor> # Continue a paginated list.
wspc email ls --include-deleted # Include soft-deleted emails.
wspc email show em_xxx # Show one email.
wspc email show em_xxx --include-html true # Include the HTML body source.
wspc email show em_xxx --include-deleted true # Show a soft-deleted email.
wspc email read em_xxx em_yyy # Mark multiple emails as read.
wspc email unread em_xxx # Mark one email as unread.
wspc email rm em_xxx em_yyy # Soft-delete multiple emails.
wspc email restore em_xxx em_yyy # Restore one or more soft-deleted emails.
--alias-email accepts a full alias email address under @wspc.app or a fully verified organization custom domain. --since is a Unix epoch milliseconds lower bound on received_at. --limit ranges 1-100. Default 20. --cursor continues from a previous list response. Use wspc email restore <id...> to restore soft-deleted emails; it accepts 1-100 ids per call.
read, unread, rm, and restore each accept 1-100 email ids per call.
email ls, email show, email read, email unread, email rm, and email restore accept --json.
Send and reply
wspc email send \
--from mailme1@wspc.app \
--to friend@example.com \
--cc teammate@example.com \
--bcc archive@example.com \
--subject "Hello" \
--text "Hi from wspc" \
--idempotency-key hello-001
# Send a short plain-text email with separate To, CC, and BCC roles.
wspc email send \
--from mailme@wspc.app \
--to friend@example.com \
--subject "Longer note" \
--text-file ./body.txt \
--idempotency-key retry-20260515-001
# Send a longer email from a file and make retries safe.
wspc email send --reply em_xxx --from mailme1@wspc.app --text-file ./reply.txt --idempotency-key reply-001
# Reply to an existing email using file content (reply mode via --reply).
wspc email send \
--from mailme1@wspc.app \
--to friend@example.com \
--subject "Invoice" \
--text "Attached." \
--attach ./invoice.pdf \
--idempotency-key invoice-001
# Send with a local attachment.
wspc email send --reply em_xxx \
--from mailme1@wspc.app \
--text "Forwarding the original attachment." \
--attach em_xxx:0 \
--idempotency-key fwd-001
# Reuse an existing inbound attachment by <email_id>:<idx> reference.
--from accepts a full active alias email address under @wspc.app or a fully verified organization custom domain. Sending is restricted to active aliases; custom-domain sending requires sending_status = verified. --to, --cc, and --bcc accept recipient addresses and are repeatable; a fresh send preserves each recipient role and its input order. Use either --text or --text-file; --text-file handles longer bodies. --idempotency-key is required. The full replay result is available until the returned idempotency_expires_at (at most 30 days from the initial send) unless emptying sent-message trash revokes it earlier. After expiry or revocation, the same key and payload returns IDEMPOTENT_RESULT_PURGED and is never sent again; reusing the key with changed content still returns IDEMPOTENCY_KEY_REUSED. Reply mode is email send --reply <inbound-email-id> (there is no separate email reply command); it derives recipients, subject, and threading from the original. The CLI rejects --cc or --bcc together with --reply before it sends a request.
--attach accepts either a local file path (the CLI reads it, infers content type from the extension, and base64-encodes it) or a reference to an existing inbound attachment in <email_id>:<idx> format (reused without round-tripping bytes through the CLI). It is repeatable.
email send accepts --json.
Attachments
wspc email attachment em_xxx 0 # Download attachment 0 to its original filename.
wspc email attachment em_xxx 0 --output invoice.pdf # Save attachment 0 to a chosen path.
wspc email attachment em_xxx 0 --force # Overwrite the output file if it exists.
wspc email attachment em_xxx 0 --include-deleted # Download from a soft-deleted email.
wspc email attachment em_xxx 0 --json # Print download metadata as JSON.
Without --output, the CLI writes to the original filename in the current directory. Existing files are not overwritten by default. Pass --force to overwrite.
// 09 — Push
Push
Push forwards agent results to an always-on transport so long-running work can notify you after the CLI session has moved on. The current transport is Telegram in agent-bot mode.
wspc push config set --transport telegram --target-bot-username @user_openclaw_bot
# Store Telegram push config.
wspc push config show # Show configured push transports.
wspc push config rm telegram # Remove a push transport by name.
wspc push test # Send a test message through the default telegram transport.
wspc push test --transport telegram # Send a test message through an explicit transport.
--transport currently accepts telegram. --target-bot-username is the Telegram agent bot username, for example @user_openclaw_bot. push config rm takes the transport name as a positional argument.
push config set, push config show, and push test accept --json.
// 10 — Guided tour
Guided tour
wspc tour # Print the guided-tour script for your AI agent to read and follow.
wspc tour fetches the tour from wspc and prints it. When you run it in an
interactive terminal it adds a one-line hint reminding you the script is meant
for your AI agent; when captured by an agent (piped) it prints only the script.