DingTalk Workspace CLI (dws)
dws — DingTalk Workspace on the command line, built for humans and AI agents.
中文版 · English · Reference · Changelog
> [!IMPORTANT]
> **Co-creation Phase**: This project accesses DingTalk enterprise data and requires enterprise admin authorization. Join the DingTalk DWS co-creation group for support and updates. See [Getting Started](#getting-started) below.
>
>
Table of Contents
- [Why dws?](#why-dws)
- [Installation](#installation)
- [Upgrade](#upgrade)
- [Getting Started](#getting-started)
- [Quick Start](#quick-start)
- [Using with Agents](#using-with-agents)
- [Features](#features)
- [Key Services](#key-services)
- [Security by Design](#security-by-design)
- [Reference & Docs](#reference--docs)
- [Contributing](#contributing)
---
Why dws?
- **For humans** — `--help` for usage, `--dry-run` to preview requests, `-f table/json/raw` for output formats.
- **For AI agents** — structured JSON responses + built-in Agent Skills, ready out of the box.
- **For enterprise admins** — zero-trust architecture: OAuth device-flow auth + domain allowlisting + least-privilege scoping. **Not a single byte can bypass authentication and audit.**
## Installation
**macOS / Linux:**
```bash
curl -fsSL https://raw.githubusercontent.com/DingTalk-Real-AI/dingtalk-workspace-cli/main/scripts/install.sh | sh
```
> Linux binaries are linked against glibc (baseline 2.17). musl-based distributions such as Alpine are not supported; the installer detects them and stops instead of installing a binary that cannot start.
**Windows (PowerShell):**
```powershell
irm https://raw.githubusercontent.com/DingTalk-Real-AI/dingtalk-workspace-cli/main/scripts/install.ps1 | iex
```
Skill mode: mono vs multi
The installer ships skills in one of two layouts. CLI commands (`dws aitable ...`, `dws calendar ...`) are identical in both modes — only the agent-side skill layout differs.
| Mode | What gets installed | Best for |
|------|----------------------|----------|
| **multi** (default) | Per-product skills (`dingtalk-aitable`, `dingtalk-calendar`, `dingtalk-chat`, ...) | Single-product tasks; smaller context per call |
| **mono** (legacy) | One `dws` skill covering all products | Cross-product workflows; single entry point |
> Installs and upgrades default to `multi`. `mono` remains available via `DWS_SKILL_MODE=mono` or `dws skill setup --mode mono`. File issues if you hit problems.
How to pick:
- **Quick install** (one-liner above): non-interactive, installs `multi`.
- **TTY install** (download then run): `curl -O .../install.sh && bash install.sh` — prompts `1) multi 2) mono` (default 1).
- **Override via env**: `DWS_SKILL_MODE=mono curl -fsSL ... | sh`.
- **Switch later**: `dws skill setup --mode mono` (or `--mode multi`) — review the listed paths and confirm interactively.
Other install methods
**npm** (requires Node.js (npm/npx)):
```bash
npm install -g dingtalk-workspace-cli
```
Install the latest beta:
```bash
npm install -g dingtalk-workspace-cli@beta
```
**Homebrew** (macOS / Linux):
```bash
brew tap DingTalk-Real-AI/dingtalk-workspace-cli https://github.com/DingTalk-Real-AI/dingtalk-workspace-cli.git
brew install dingtalk-workspace-cli
```
> The Formula lives in this repository, so the first `tap` command must include the explicit repository URL. Afterwards, use `brew upgrade dingtalk-workspace-cli` normally.
Install the keg-only Homebrew beta without replacing the stable Formula:
```bash
brew install dingtalk-workspace-cli-beta
$(brew --prefix dingtalk-workspace-cli-beta)/bin/dws version
```
To make the beta `dws` the default for the current shell, prepend `$(brew --prefix dingtalk-workspace-cli-beta)/bin` to PATH.
**Pre-built binary**: download from [GitHub Releases](https://github.com/DingTalk-Real-AI/dingtalk-workspace-cli/releases).
> **macOS users**: If you see "cannot be opened because Apple cannot check it for malicious software", run:
> ```bash
> xattr -d com.apple.quarantine /path/to/dws
> ```
**Build from source**:
```bash
git clone https://github.com/DingTalk-Real-AI/dingtalk-workspace-cli.git
cd dingtalk-workspace-cli
go build -o dws ./cmd # build to current directory
cp dws ~/.local/bin/ # install to PATH
```
Static endpoint data is generated from the Wukong baseline and committed in this
repository under `internal/syncdata`, so source builds do not require a sibling
data checkout.
> Requires Go 1.25+. On supported macOS, Linux, and Windows amd64/arm64 hosts,
> the default CGO build includes the SafeChat backend without a build tag and
> therefore requires a working C compiler. Set `CGO_ENABLED=0` only when a stub
> build is intentional. Use `make package` with Docker to build all six release
> targets through the repository's pinned cross-compilation toolchain.
## China mirror
For users in mainland China, the following channels avoid GitHub network issues. By default (without setting these environment variables) the installer pulls from GitHub.
**1. Install script + pre-built binary (Gitee mirror):**
Repository mirror: `https://gitee.com/DingTalk-Real-AI/dingtalk-workspace-cli`
```bash
DWS_GITEE_REPO=DingTalk-Real-AI/dingtalk-workspace-cli curl -fsSL https://gitee.com/DingTalk-Real-AI/dingtalk-workspace-cli/raw/main/scripts/install.sh | sh
```
> With `DWS_GITEE_REPO` set, the installer resolves the latest version and every release asset (binary, checksums, skills) from the Gitee API instead of GitHub. If it is unset, installation defaults to GitHub.
**2. npm package (npmmirror mirror):**
```bash
npm install -g dingtalk-workspace-cli --registry=https://registry.npmmirror.com
```
> npmmirror automatically syncs public packages from the public npm registry, so this works directly in China.
**3. Skills only (Gitee mirror):**
```bash
DWS_GITEE_REPO=DingTalk-Real-AI/dingtalk-workspace-cli curl -fsSL https://gitee.com/DingTalk-Real-AI/dingtalk-workspace-cli/raw/main/scripts/install-skills.sh | sh
```
> With `DWS_GITEE_REPO` set, `install-skills.sh` resolves the version and skills package from Gitee; it also auto-falls back to the Gitee mirror when GitHub is unreachable.
## Upgrade
> Requires **v1.0.7** or later. For earlier versions, please re-run the [install script](#installation) to upgrade.
dws has built-in self-upgrade capability. Updates are pulled directly from [GitHub Releases](https://github.com/DingTalk-Real-AI/dingtalk-workspace-cli/releases) with SHA256 integrity verification and automatic backup.
```
…
```
By default, `dws upgrade` follows the stable release track. Use `--beta` only when you explicitly want the newest GitHub pre-release build.
### Six-channel post-release verification
Maintainers and release validators can run the release-quality smoke checks for curl, PowerShell, npm stable, npm beta, Homebrew, and `dws upgrade`:
```bash
git clone https://github.com/DingTalk-Real-AI/dingtalk-workspace-cli.git /tmp/dws-verify
cd /tmp/dws-verify/verify
bash verify-all-channels.sh
```
The verifier uses isolated directories and does not replace the `dws` on the current PATH. It reports `PASS`, `FAIL`, and `SKIP`; a platform skip is not a pass and must be covered on the matching host. See [`verify/README.md`](verify/README.md) for the platform matrix.
How it works
The upgrade process follows a two-phase atomic flow to ensure consistency:
1. **Prepare** — downloads the platform-specific binary and skill packages to a temporary directory, verifies SHA256 checksums, and extracts/validates all files. If any step fails, the upgrade aborts without modifying the existing installation.
2. **Apply** — only after all preparations succeed, the binary is replaced and skills are flattened into the canonical `~/.agents/skills` root. Agents classified by the pinned compatibility registry as supporting the universal root read it directly; other detected Agents receive links to the canonical copy, with a direct-copy fallback when links are unavailable. Older DWS-managed agent-specific copies are backed up and retired so the same Skill is not discovered twice.
A backup of the current version is automatically created before each upgrade. Use `dws upgrade --rollback` to restore the previous version if needed.
| Flag | Description |
|------|-------------|
| `--check` | Check for updates without installing |
| `--list` | List available stable release versions with changelogs |
| `--beta` | Use the beta pre-release track for `upgrade`, `--check`, or `--list` |
| `--version` | Upgrade to a specific version (e.g. `v1.0.7` or `v1.0.8-beta.1`) |
| `--rollback` | Rollback to the previous backed-up version |
| `--force` | Force reinstall even if already on the latest version |
| `--skip-skills` | Skip skill package update |
| `-y` | Skip confirmation prompt |
## Getting Started
```bash
dws auth login # browser opens automatically
dws auth login --device # for headless environments (Docker, SSH, CI)
```
Select your organization and authorize. That's it.
> If your organization hasn't enabled CLI access, you'll be prompted to send an access request to your admin. Once approved, re-run `dws auth login`.
Organization hasn't enabled CLI access?
1. After selecting your organization, click "Apply Now" to notify the admin
2. The admin receives a request card and can approve with one click
3. Once approved, re-run `dws auth login`
Admin: Enable CLI access for your organization
Go to [Developer Platform](https://open-dev.dingtalk.com) → "CLI Access Management" → Enable.
Custom App mode (CI/CD, ISV integration)
For enterprise-managed scenarios, create your own DingTalk app:
1. [Open Platform Console](https://open-dev.dingtalk.com/fe/app#/corp/app) → Create App
2. Security Settings → Add redirect URLs: `http://127.0.0.1,https://login.dingtalk.com`
3. Publish the app
4. Login:
```bash
dws auth login --client-id --client-secret
```
Credentials are securely persisted after first login (Keychain). Subsequent runs auto-refresh tokens.
Multiple organizations (profiles)
`dws` can stay logged in to several DingTalk accounts at once, including multiple accounts in the same organization. A profile is uniquely identified by `corpId:userId`; the current profile decides which identity a command runs as.
```bash
dws auth login # add or refresh one account
dws profile list # list every logged-in account
dws profile switch # persistently switch; use - to toggle back
dws profile switch ":" # friendly input; names must be unique
dws --profile contact user search --query "..." # use that org's explicitly recorded current account
dws --profile contact user search --query "..." # use one exact account without changing the default
```
Selectors support `corpId:userId`, `corpId:userName`, `corpName:userId`, and `corpNam