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. Please join the DingTalk DWS co-creation group to complete whitelist configuration. See Getting Started below.

Table of Contents
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:
curl -fsSL https://raw.githubusercontent.com/DingTalk-Real-AI/dingtalk-workspace-cli/main/scripts/install.sh | sh
Windows (PowerShell):
irm https://raw.githubusercontent.com/DingTalk-Real-AI/dingtalk-workspace-cli/main/scripts/install.ps1 | iex
Other install methods
Pre-built binary: download from GitHub Releases.
Build from source:
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
Requires Go 1.25+. Use make package to cross-compile for all platforms (macOS / Linux / Windows x amd64 / arm64).
Getting Started
Step 1: Create a DingTalk Application
Go to the Open Platform Console. Under "Internal Enterprise Apps - DingTalk Apps", click Create App.
View screenshot
Go to app settings → Security Settings. Add the following redirect URLs and save:
http://127.0.0.1
https://login.dingtalk.com
http://127.0.0.1 is for local browser login; https://login.dingtalk.com is for --device device-flow login (Docker containers, remote servers, and other headless environments). We recommend configuring both.
View screenshot
Step 3: Publish the Application
Click "App Release - Version Management & Release" to publish and go live.
View screenshot
Step 4: Request Whitelist Access
Join the DingTalk DWS co-creation group and provide your Client ID and admin confirmation to complete whitelist setup.
Step 5: Authenticate
dws auth login --client-id <your-app-key> --client-secret <your-app-secret>
Or via environment variables:
export DWS_CLIENT_ID=<your-app-key>
export DWS_CLIENT_SECRET=<your-app-secret>
dws auth login
Credential Configuration Priority
client-id and client-secret support multiple configuration methods with the following priority (highest to lowest):
| Priority |
Method |
Description |
| 1 |
CLI flags / Persisted config |
--client-id / --client-secret command-line arguments; auto-saved after first successful login with client-secret stored in system Keychain |
| 2 |
Environment variables |
DWS_CLIENT_ID / DWS_CLIENT_SECRET |
| 3 |
Default values |
Hardcoded defaults (for development only) |
Recommended usage:
- First login: Use
--client-id and --client-secret flags; credentials are securely persisted after successful login
- Subsequent use: Run
dws commands directly; token refresh automatically reads saved credentials from Keychain
- CI/CD environments: Use environment variables
Quick Start
dws contact user search --keyword "engineering" # search contacts
dws calendar event list # list calendar events
dws todo task create --title "Quarterly report" --executors "<your-userId>" # create a todo (replace <your-userId>)
dws todo task list --dry-run # preview without executing
Using with Agents
dws is designed as an AI-native CLI. Complete Installation and Getting Started first, then configure your agent:
# Configure auth via environment variables (recommended for agents, no interactive login)
export DWS_CLIENT_ID=<your-app-key>
export DWS_CLIENT_SECRET=<your-app-secret>
dws auth login
Agent Invocation Patterns
# Use --yes to skip confirmation prompts (required for agents)
dws todo task create --title "Review PR" --executors "<your-userId>" --yes
# Use --dry-run to preview operations (safe execution)
dws contact user search --keyword "engineering" --dry-run
# Use --jq to extract precisely (save tokens)
dws contact user get-self --jq '.result[0].orgEmployeeModel | {name: .orgUserName, dept: .depts[0].deptName, userId}'
Schema Discovery
Agents don't need pre-built knowledge of every command. Use dws schema to dynamically discover capabilities:
# Step 1: Discover all available products
dws schema --jq '.products[] | {id, tool_count: (.tools | length)}'
# Step 2: Inspect target tool's parameter schema
dws schema aitable.query_records --jq '.tool.parameters'
# Step 3: Construct the correct call
dws aitable record query --base-id BASE_ID --table-id TABLE_ID --limit 10
Agent Skills
The repo ships a complete Agent Skill system (skills/). After installing, AI tools like Claude Code / Cursor can operate DingTalk directly through natural language:
# Install skills into current project
curl -fsSL https://raw.githubusercontent.com/DingTalk-Real-AI/dingtalk-workspace-cli/main/scripts/install-skills.sh | sh
install.sh installs to $HOME/.agents/skills/dws (global); install-skills.sh installs to ./.agents/skills/dws (current project).
What's included:
| Component |
Path |
Description |
| Master Skill |
SKILL.md |
Intent routing, decision tree, safety rules, error handling |
| Product references |
references/products/*.md |
Per-product command reference (aitable, chat, calendar, etc.) |
| Intent guide |
references/intent-guide.md |
Disambiguation for confusing scenarios (e.g. report vs todo) |
| Global reference |
references/global-reference.md |
Auth, output formats, global flags |
| Error codes |
references/error-codes.md |
Error codes + debugging workflows |
| Recovery guide |
references/recovery-guide.md |
RECOVERY_EVENT_ID handling |
| Ready-made scripts |
scripts/*.py |
13 batch operation scripts (see below) |
Ready-made scripts — 13 Python scripts for common multi-step workflows
| Script |
Description |
calendar_schedule_meeting.py |
Create event + add participants + find & book available meeting room |
calendar_free_slot_finder.py |
Find common free slots across multiple people, recommend best meeting time |
calendar_today_agenda.py |
View today/tomorrow/this week's schedule |
import_records.py |
Batch import records from CSV/JSON into AITable |
bulk_add_fields.py |
Batch add fields to an AITable data table |
upload_attachment.py |
Upload attachment to AITable attachment field |
todo_batch_create.py |
Batch create todos from JSON (with priority, due date, executors) |
todo_daily_summary.py |
Summarize today/this week's incomplete todos |
todo_overdue_check.py |
Scan overdue todos and output overdue list |
contact_dept_members.py |
Search department by name and list all members |
attendance_my_record.py |
View my attendance records for today/this week/specific date |
attendance_team_shift.py |
Query team shift schedules and attendance statistics |
report_inbox_today.py |
View today's received reports with details |
ISV Integration: Author your own Agent Skills and orchestrate them with dws skills for cross-product workflows: ISV Skill → dws Skill → DingTalk Open Platform API (enforced auth + full audit).
Features
Smart Input Correction — auto-corrects common AI model parameter mistakes v1.0.1
Built-in pipeline engine that normalizes flag names, splits sticky arguments, and fuzzy-matches typos:
# Naming convention auto-conversion (camelCase / snake_case / UPPER -> kebab-case)
dws aitable record query --baseId BASE_ID --tableId TABLE_ID # auto-corrected to --base-id --table-id
# Sticky argument splitting
dws contact user search --keyword "engineering" --timeout30 # auto-split to --timeout 30
# Fuzzy flag name matching
dws aitable record query --base-id BASE_ID --tabel-id TABLE_ID # --tabel-id -> --table-id
# Value normalization (boolean / number / date / enum)
# "yes" -> true, "1,000" -> 1000, "2024/03/29" -> "2024-03-29", "ACTIVE" -> "active"
| Agent Output |
dws Auto-Corrects To |
--userId |
--user-id |
--limit100 |
--limit 100 |
--tabel-id |
--table-id |
--USER-ID |
--user-id |
--user_name |
--user-name |
jq Filtering & Field Selection — fine-grained output control to reduce token consumption v1.0.1
# Built-in jq expressions
dws aitable record query --base-id BASE_ID --table-id TABLE_ID --jq '.invocation.params'
dws schema --jq '.products[] | {id, tools: (.tools | length)}'
# Return only specific fields
dws aitable record query --base-id BASE_ID --table-id TABLE_ID --fields invocation,response
Schema Introspection — query parameter schemas before making calls v1.0.1
dws schema # list all products and tools
dws schema aitable.query_records # view parameter schema
dws schema aitable.query_records --jq '.tool.required' # view required fields
dws schema --jq '.products[].id' # extract all product IDs
Pipe & File Input — read flag values from files or stdin v1.0.1
# Read message body from a file
dws chat message send-by-bot --robot-code BOT_CODE --group GROUP_ID \
--title "Weekly Report" --text @report.md
# Pipe content via stdin
cat report.md | dws chat message send-by-bot --robot-code BOT_CODE --group GROUP_ID \
--title "Weekly Report"
# Read from stdin explicitly
dws chat message send-by-bot --robot-code BOT_CODE --group GROUP_ID \
--title "Weekly Report" --text @-
Key Services
| Service |
Command |
Tools |
Subcommands |
Description |
| Contact |
contact |
8 |
user dept |
Search users by name/mobile, batch query, departments, current user profile |
| Chat |
chat |
14 |
message group bot search |
Group CRUD, member management, message history, topic replies, send as user |
| Bot |
chat bot |
9 |
— |
Robot creation, group/single messaging, webhook, message recall |
| Calendar |
calendar |
13 |
event room participant busy |
Events CRUD, meeting room booking, free-busy query, participant management |
| Todo |
todo |
6 |
task |
Create, list, update, done, get detail, delete |
| Approval |
oa |
9 |
approval |
Approve/reject/revoke, pending tasks, initiated instances, process list |
| Attendance |
attendance |
4 |
record shift summary rules |
Clock-in records, shift schedules, attendance summary, group rules |
| Ding |
ding |
3 |
message |
Send/recall DING messages |
| Report |
report |
7 |
create list detail template stats sent |
Create reports, sent/received list, templates, statistics |
| AITable |
aitable |
27 |
base table record field attachment template |
Full CRUD for bases/tables/records/fields, views, import/export, templates |
| Workbench |
workbench |
2 |
app |
Batch query app details |
| DevDoc |
devdoc |
2 |
article |
Search platform docs and error codes |
104 tools across 12 products. Run dws --help for the full list, or dws <service> --help for subcommands.
Coming soon
doc (documents) · mail (email) · minutes (AI transcription) · drive (cloud drive) · conference (video) · tb (Teambition) · aiapp (AI apps) · live (streaming) · skill (marketplace)
Security by Design
dws treats security as a first-class architectural concern, not an afterthought. Credentials never touch disk, tokens never leave trusted domains, permissions never exceed grants, operations never escape audit — every API call must pass through DingTalk Open Platform's authentication and audit chain, no exceptions.
For Developers
| Mechanism |
Details |
| Encrypted token storage |
PBKDF2 + AES-256-GCM encryption, keyed by device physical MAC address; cross-platform Keychain/DPAPI integration provides additional protection — tokens cannot be decrypted on another machine |
| Input security |
Path traversal protection (symlink resolution + working directory containment), CRLF injection blocking, Unicode visual spoofing filtering — prevents AI Agents from being tricked by malicious instructions |
| Domain allowlist |
DWS_TRUSTED_DOMAINS defaults to *.dingtalk.com; bearer tokens are never sent to non-allowlisted domains |
| HTTPS enforced |
All requests require TLS; HTTP only permitted for loopback during development |
| Dry-run preview |
--dry-run shows call parameters without executing, preventing accidental mutations |
| Zero credential persistence |
Client ID / Secret used in memory only — never written to config files or logs |
For Enterprise Admins
| Mechanism |
Details |
| OAuth device-flow auth |
Users must authenticate through an admin-authorized DingTalk application |
| Least-privilege scoping |
CLI can only invoke APIs granted to the application — no privilege escalation |
| Allowlist gating |
Admin confirmation required during co-creation phase; self-service approval planned |
| Full-chain audit |
Every data read/write passes through the DingTalk Open Platform API — enterprise admins can trace complete call logs in real time; no anomalous operation can hide |
For ISVs
| Mechanism |
Details |
| Tenant data isolation |
Operates under authorized app identity; cross-tenant access is impossible |
| Skill sandbox |
Agent Skills are Markdown documents (SKILL.md) — prompt descriptions only, no arbitrary code execution |
| Zero blind spots |
Every API call during ISV–dws skill orchestration is forced through DingTalk Open Platform authentication — full call chain is traceable with no bypass path |
Found a vulnerability? Report via GitHub Security Advisories. See SECURITY.md.
Reference & Docs
- Reference — environment variables, exit codes, output formats, shell completion
- Architecture — discovery-driven pipeline, IR, transport layer
- Changelog — release history and migration notes
Contributing
See CONTRIBUTING.md for build instructions, testing, and development workflow.
License
Apache-2.0