wanas-zone-cli
v0.8.3
Published
zone — one CLI for the whole Zoho suite: CRM, Mail, Meeting, Books, Inventory, Creator, Partner Store, Social, Projects, Desk, Sign, Writer, Sheet, Learn, TrainerCentral, People, Campaigns, Marketing Automation, WorkDrive, Cliq and Survey. Unified OAuth,
Maintainers
Readme
One CLI for the whole Zoho suite. zone signs you in once and gives you 9,909 typed commands across 64 services — CRM, Books, Desk, Mail, Projects, Inventory, People, WorkDrive, Cliq, Campaigns, Creator, Catalyst, Zoho One, Payments, Contracts, Connect and the rest — plus a raw proxy for any endpoint the typed commands miss. Auth, token refresh, datacenter routing, org/portal context and pagination are handled once, in one place. It is built for coding agents as much as for people: data on stdout, messages on stderr, a JSON error envelope, meaningful exit codes, a dry-run switch and a policy gate that make it safe to hand to an AI tool pointed at a live client org.
npm install -g wanas-zone-cliContents
Install and first call · The model · Agent contract · Safety · Skills for AI tools · Finding a command · Services · Authentication · Environment variables · Troubleshooting · Development · Changelog · Support
Install and first call
npm install -g wanas-zone-cli
zone login crm # one browser consent; add more services any timeThe first real call — a COQL count against your own CRM:
zone crm coql "select COUNT(id) as leads from Leads where id is not null" --json{
"data": [
{
"leads": 4424
}
],
"info": {
"count": 1,
"more_records": false
}
}If an AI coding tool will drive zone, install the skills before you ask it for Zoho work. No model knows 9,909 commands from memory; the skills carry the real names, required flags, payload shapes and the traps found on live orgs. Install the skills BEFORE the first prompt — it is one command:
zone skill # this project (interactive picker for the agent)
zone skill --global # once, for every project on this machinePrefer not to install globally? npx wanas-zone-cli <command> works too.
The model
Five ideas cover almost everything zone does.
One login, many services. zone login crm books desk opens one consent for the named services (--all takes every core service in one go; extended services are named explicitly). Zoho issues one shared grant; each service gets its own session file under .zone/sessions/, so a token problem in one never touches another. Refresh is automatic.
Sessions are per project. zone login writes to ./.zone, found the way git finds .git — by walking up from the current directory. Each client repo carries its own Zoho identity and cd switches org with no re-login. --global uses ~/.zone; ZONE_HOME overrides both. .zone directories self-ignore in git.
Typed commands, with a proxy underneath. Every command has the shape zone <service> <group> <name> [args] [flags]:
zone crm record list Leads --fields Last_Name,Company --per-page 5
zone books invoice list --per-page 5 --toon
zone mail folder list --toon
zone crm coql "select id, Deal_Name from Deals where Stage = 'Closed Won'"Anything not typed yet is one call away through the same client, with the same auth, refresh, datacenter routing and 401 retry:
zone api crm GET /Leads --query fields=Last_Name,Company --query per_page=5
zone api crm GET /org --out org.json
echo '{"data":[{"Last_Name":"Doe"}]}' | zone api crm POST /Leads --data - --dry-run--data takes inline JSON, @file, or - for stdin; --form k=v sends urlencoded fields; --out saves raw bytes.
Context is injected for you. Zoho scopes calls inconsistently — Books wants organization_id in the query, Desk an orgId header, Projects a portal id in the path. Store each once and every later call carries it; an explicit --query organization_id=... always wins.
zone ctx books organization_id=847058403
zone ctx desk orgId=700123456
zone ctx books # show what is storedCRM sandbox and developer edition. Zoho CRM serves the same API on three hosts — production (www.zohoapis.<dc>), the org's sandbox (sandbox.zohoapis.<dc>) and the developer edition (developer.zohoapis.<dc>) — and binds every OAuth token to the organization picked on the consent screen. Log in to the sandbox in its own store (ZONE_HOME=./.zone-sandbox zone login crm, choose the Sandbox organization): zone asks the org which environment it is (GET /org → type), stores env=sandbox, and every zone crm … command, zone api crm, bulk, functions and the absolute-URL rows go to the sandbox host. zone status grows an ENV column while any service is off production (and shows SANDBOX ≠ token production when the context and the token disagree), each command prints one stderr line naming the environment, and --dry-run reports environment and base. zone ctx crm env=… moves the host by hand and warns when the stored token is bound elsewhere; a production token on the sandbox host gets DOMAIN_TOKEN_MISMATCH with the fix in its hint.
Output is a contract. Data goes to stdout, messages to stderr, so a pipe is never polluted. --json renders JSON; --toon renders TOON, a compact form that costs an LLM 30–60% fewer tokens for the same data. Both wrap plain-text responses so JSON.parse(stdout) always works. The rest of that contract is the next section.
Agent contract
zone's primary users are coding agents. What they can rely on:
stdout is data, stderr is messages. Progress, hints and warnings never land in the data stream;
-qsilences them.Exit codes mean something.
| Code | Meaning | What a caller should do | |--:|---|---| |
0| success | parse stdout | |1| unexpected error | report it (zone bug) | |2| usage error — bad flags, bad input, missing argument | fix the command;--helphas the shape | |3| not authenticated | a human must runzone login| |4| missing OAuth scope | re-login that service | |5| Zoho rejected the request (4xx) | read thezohobody; do not retry blindly | |6| blocked by policy | report it; the rule that blocked is named | |7| retryable — network, 429, 5xx | back off and retry |The last stderr line is JSON on failure when
--jsonor--toonis set (orZONE_JSON_ERRORS=1):{"ok":false,"error":{code,message,hint,http_status,zoho,context}}. Commander's own usage errors are included, so a missing argument parses the same way a Zoho error does:zone --json crm record get{"ok":false,"error":{"code":"BAD_INPUT","message":"missing required argument 'module'","hint":"Run \"zone --help\" or \"zone <command> --help\" for the exact arguments and flags.","http_status":null,"zoho":null,"context":null}}Help is machine-readable too.
zone crm record create --help --jsonreturns the arguments (withrequired), options and subcommands as a JSON shape, so an agent can learn a command without parsing prose.hintis the fix. Every structured error that has a known remedy names it — the missing flag, thezone ctxline to run, thezone loginto redo.API versions fall back on their own. Zoho serves several CRM API versions side by side and they drift: a path dropped from v9 still answers on v8, and a settings config that 500s on v9 and v8 reads in full on v7. When a call fails with a drift signature (
404 INVALID_URL_PATTERN, "deprecated in this version", or a500 INTERNAL_ERRORon a read), zone walks v9 → v8 → v7 → … → v2 until one answers, never below a row's minimum version, and prints one line naming the version that served it with the--api-versionpin to make it permanent. Writes are only replayed for the 404 case (nothing ran). An explicit--api-versionorZONE_API_FALLBACK=0switches it off; if every version fails, the error carriesversions_triedand says so.Throttling is handled the way Zoho documents it. CRM meters API credits over a rolling 24 hours plus a concurrency cap; the finance apps allow 100 requests a minute per organization plus a daily cap; all of it arrives as HTTP 429. zone waits out
Retry-Afteror the rate-limit reset header (else exponential backoff) and retries up toZONE_RETRIEStimes, each wait capped atZONE_RETRY_MAX_WAIT_MS; a reset hours away, or Books' daily-limit code 45, fails fast instead. Connection failures and 5xx are retried for reads only — a write may already have been applied. Exit 7 means the limit did not clear: the error carriesrate_limit.reset_at, andzone statusshows the quota each service last reported.
Safety
zone is the tool an agent calls to reach live client orgs, so the safety properties a harness would normally provide have to live here — a harness granting shell(zone) has granted every write to every authenticated service and cannot express "reads only".
--dry-run works on every command. A mutating request is resolved and printed instead of sent, exit 0. Reads still run, so an agent can leave it on while building a call. zone bug honours it too.
zone crm record delete Leads 123 --dry-run --json{
"dry_run": true,
"service": "crm",
"method": "DELETE",
"path": "/Leads/123",
"query": {},
"body": null,
"api_version": null
}Policy gate. --allow / --deny (or ZONE_POLICY / ZONE_POLICY_DENY) match service:METHOD with * on either side. Deny always wins; no policy means no restriction. A blocked call exits 6 and names the rule. Classification is by what an endpoint does, not its verb: COQL and bulk read are POSTs that count as reads, and the Campaigns / Marketing Automation writes that Zoho serves over GET count as writes — so *:GET really is read-only.
ZONE_POLICY='*:GET' zone crm record create Leads --data '{"data":[{"Last_Name":"x"}]}' --jsonerror: Blocked by policy: crm:POST /Leads — not in the allow list.
hint: Add "crm:POST" (or "crm:*") to the allow list to permit this.
{"ok":false,"error":{"code":"POLICY_DENIED","message":"Blocked by policy: crm:POST /Leads — not in the allow list.","hint":"Add \"crm:POST\" (or \"crm:*\") to the allow list to permit this.","http_status":null,"zoho":null,"context":null}}Secret redaction, on by default. Fields named like credentials (access_token, client_secret, password, api_key, …) are masked on every path out — stdout, --verbose details and the machine error line alike — and the literal value of any ZONE_* secret in the environment is scrubbed from free text. zone token is exempt because emitting the token is the command; zone vault takes --reveal, refused under --json/--toon or off a TTY unless ZONE_REVEAL_UNSAFE=1.
Audit log. --audit <file> (or ZONE_AUDIT) appends one JSONL line per request — real, denied or dry-run — with the method, path, effect (read/write), status and timing. Metadata only, never a body. A write failure warns once and never fails the command.
{"ts":"2026-09-04T16:35:54.367Z","service":"crm","method":"DELETE","path":"/Leads/1","effect":"write","status":null,"outcome":"denied","policy":"denied","dry_run":false,"ms":null,"pid":40992}One seam, no bypasses. Every request — declarative rows, the zone api proxy, every stateful handler, every file upload and download — goes through src/core/apiClient.js. A test fails if any raw HTTP call in the tree sits outside that gate. The same seam refuses ./.. path segments, refuses to attach a token to a non-Zoho host, and treats an HTML page where JSON was expected as an error rather than a result.
Skills for AI tools
zone skill writes skill files where your agent already looks — no plugin, no MCP server, no config. Each per-service skill carries that service's real commands, the flags Zoho requires, where a --data body goes, base URL, context ids and quirks, generated from the installed CLI; 21 services add a hand-written guide of live-org behaviour (CRM, Books, Inventory, Desk, Projects, Mail, WorkDrive, Sheet, Writer, Meetings, Social, People, Sprints, Invoice, Billing, Analytics, Cliq, SalesIQ, Partner, Commerce, Payroll). Only a skill's one-line description is resident on each prompt; the body loads when it triggers, so an agent pays for the service it is using rather than for all 64.
zone skill --ide claude # all skills into .claude/skills/ (add --global for every project)
zone skill crm --ide cursor # one service as .cursor/rules/zoho-crm.mdc
zone skill deluge --ide codex # a marked section in AGENTS.md — never overwrites your own text
zone skill --stdout # print instead of writing (pipe into any agent config)| Agent / IDE | --ide | Project file | --global file |
|---|---|---|---|
| Claude Code | claude | .claude/skills/<skill>/SKILL.md | ~/.claude/skills/… |
| Antigravity / Gemini Agent | antigravity | .agents/skills/<skill>/SKILL.md | ~/.agents/skills/… |
| Cursor | cursor | .cursor/rules/<skill>.mdc | — (paste into Settings › Rules) |
| Windsurf / Cascade | windsurf | .windsurfrules | ~/.codeium/windsurf/memories/global_rules.md |
| GitHub Copilot | copilot | .github/copilot-instructions.md | — (per repository) |
| Cline / Roo Code | cline | .clinerules | ~/Documents/Cline/Rules/zoho-zone.md |
| Gemini CLI | gemini | GEMINI.md | ~/.gemini/GEMINI.md |
| Codex / any AGENTS.md tool | codex | AGENTS.md | ~/.codex/AGENTS.md |
| Anything else | markdown | ZOHO_ZONE_AI_CONTEXT.md | ~/ZOHO_ZONE_AI_CONTEXT.md |
Per-skill targets (Claude, Antigravity, Cursor) get one file per topic: the router, the Deluge language guide with its full reference, one per service, the delivery workflow, accounting safety, and the CRM widget subtypes. Shared-file targets (AGENTS.md, GEMINI.md, .clinerules, .windsurfrules, Copilot) have no trigger mechanism, so there zone skill adds the router and Deluge as marked sections and a service is added when you name it (zone skill crm --ide codex). Sections are rewritten in place between their own begin/end markers; text you wrote is never touched, and a per-skill file you wrote yourself is refused without --force. Re-run zone skill after upgrading zone.
For agents without file-based rules, zone llm prints the same guide to stdout (zone llm crm for one service, zone llm core for the router only).
Finding a command
You never have to leave the terminal, and you do not need an inventory:
zone services # all 64 services, auth state, doc links
zone crm --help # a service's command groups
zone crm blueprint --help # a group's commands
zone crm blueprint create --help # arguments, flags and notes for one command (add --json for a machine shape)
zone help books # service card: scopes, base URL, context, every group and leaf, quirks
zone llm crm # the whole typed inventory for one service, agent-readableThe full list of all 9,909 commands is generated into docs/COMMANDS.md and, with method, path and scope per command plus live search, into docs/zone-commands.html (npm run gen:docs).
Services
64 services. Extended ones carry newer, larger scope sets and are excluded from zone login --all — name them explicitly (zone login desk analytics). The last column lists the first command groups; zone help <key> shows them all.
| Service | Key | Commands | Groups |
|---|---|--:|---|
| Zoho CRM | crm | 982 | record, coql, whoami, module, field, layout, … (109 groups) |
| Zoho Mail | mail | 229 | account, folder, label, mail, attach, thread, … (13 groups) |
| Zoho Meeting | meetings | 41 | org, meeting, webinar, recording, poll, report, … (9 groups) |
| Zoho Books | books | 945 | org, contact, contactperson, estimate, salesorder, invoice, … (59 groups) |
| Zoho Inventory | inventory | 598 | orgs, contact, contactperson, item, group, composite, … (51 groups) |
| Zoho Creator | creator | 29 | meta, record, bulk, fn, pull, publish |
| Zoho Partner Store | partner | 15 | leads, subscriptions, transactions, commissions, pull |
| Zoho Social | social | 36 | post, portal, brand, channel, posts, media, … (13 groups) |
| Zoho Projects | projects | 513 | portal, project, tasklist, task, timelog, event, … (52 groups) |
| Zoho Desk | desk | 969 | ticket, thread, ticket-comment, ticket-attach, ticket-time, ticket-timer, … (111 groups) |
| Zoho Sign | sign | 36 | request, template, folder, fieldtype, doctype, signgroup |
| Zoho Writer | writer | 47 | document, template, merge, bulk, combine, sign, … (8 groups) |
| Zoho Sheet | sheet | 130 | workbook, worksheet, records, table, chart, pivot, … (17 groups) |
| Zoho Learn | learn | 63 | course, lesson, hub, space, manual, article, … (10 groups) |
| TrainerCentral | training | 24 | course, chapter, lesson, material, assignment, learner, … (8 groups) |
| Zoho People | people | 447 | record, form, employee, leave, attendance, timetracker, … (52 groups) |
| Zoho Campaigns | campaigns | 91 | list, topic, campaign, coupon, contact, segment, … (18 groups) |
| Zoho Marketing Automation | marketing | 42 | list, campaign, coupon, lead, segment, tag, … (9 groups) |
| Zoho WorkDrive | workdrive | 165 | file, folder, workspace, team, user, share, … (32 groups) |
| Zoho Cliq | cliq | 159 | channel, chat, message, user, bot, buddy, … (25 groups) |
| Zoho Survey | survey | 10 | user, portal, survey, collector, distribution, webhook |
| Zoho Analytics (extended) | analytics | 182 | org, workspace, view, data, row, table, … (28 groups) |
| Zoho Bigin (extended) | bigin | 76 | record, note, user, org, meta, pipeline, … (16 groups) |
| Zoho Recruit (extended) | recruit | 78 | record, candidate, attachment, meta, user, interview, … (18 groups) |
| Zoho Billing (extended) | billing | 277 | org, customer, subscription, plan, product, addon, … (28 groups) |
| Zoho Invoice (extended) | invoice | 268 | org, contact, invoice, estimate, payment, creditnote, … (21 groups) |
| Zoho Expense (extended) | expense | 146 | expense, report, trip, category, user, setting, … (11 groups) |
| Zoho Sprints (extended) | sprints | 214 | team, project, sprint, item, epic, release, … (36 groups) |
| Zoho Bookings (extended) | bookings | 29 | workspace, service, staff, resource, availability, appointment, … (8 groups) |
| Zoho FSM (extended) | fsm | 155 | work-order, appointment, request, estimate, contact, work-type, … (30 groups) |
| Zoho SalesIQ (extended) | salesiq | 186 | portal, operator, department, brand, conversation, call, … (30 groups) |
| Zoho Vault (extended) | vault | 35 | secret, share, chamber, user, usergroup, audit, … (7 groups) |
| Zoho Calendar (extended) | calendar | 61 | calendar, event, settings, group, notification, activity, … (13 groups) |
| Zoho Contacts (extended) | contacts | 19 | contact, category |
| Zoho Tables (extended) | tables | 40 | portal, workspace, base, table, view, field, … (12 groups) |
| Zoho Commerce (extended) | commerce | 178 | store, product, order, webhook, page, import, … (35 groups) |
| Zoho Payroll (extended) | payroll | 133 | org, employee, salary, statutory, tax, payrun, … (19 groups) |
| Zoho Catalyst (extended) | catalyst | 104 | project, zcql, table, row, bulk, fn, … (22 groups) |
| Zoho Assist (extended) | assist | 18 | user, session, unattended, report |
| Zoho Lens (extended) | lens | 27 | user, session, report, schedule, org, department, … (9 groups) |
| Qntrl (extended) | qntrl | 233 | user, org, card, workspace, circuit, function, … (36 groups) |
| Zoho Voice (extended) | voice | 53 | user, log, agent, queue, powerdialer, number, … (14 groups) |
| ZeptoMail (extended) | zeptomail | 35 | domain, agent, template, suppression, email, file, … (10 groups) |
| Zoho Backstage (extended) | backstage | 80 | event, attendee, member, sponsor, portal, event-clone, … (22 groups) |
| Zoho One (extended) | one | 31 | org, field, location, designation, user, group, … (8 groups) |
| Zoho Directory (extended) | directory | 30 | geo, org, field, location, designation, user, … (8 groups) |
| Zoho Payments (extended) | payments | 55 | customer, payment-method-session, payment-method, payment-session, terminal-session, mandate, … (16 groups) |
| Zoho Webinar (extended) | webinar | 32 | org, webinar, recording, poll, report, user, … (9 groups) |
| Zoho Connect (extended) | connect | 279 | network, profile, user-follow, favourite, block, activity, … (43 groups) |
| Zoho Contracts (extended) | contracts | 86 | org, user, department, counterparty-type, counterparty, counterparty-contact, … (15 groups) |
| Zoho Shifts (extended) | shifts | 45 | org, employee, access-level, skill, shift, timesheet, … (12 groups) |
| Zoho Workerly (extended) | workerly | 18 | meta, record, timelog |
| Zoho Thrive (extended) | thrive | 2 | purchase, activity |
| Zoho POS (extended) | pos | 210 | org, contact, contact-person, item-group, item, composite-item, … (22 groups) |
| Zoho PageSense (extended) | pagesense | 20 | experiment, goal, audience, report, projectgoal, customevent |
| Zoho BugTracker (extended) | bugtracker | 86 | portal, project, activity, status, milestone, timelog, … (17 groups) |
| Zoho DataPrep (extended) | dataprep | 43 | org, workspace, pipeline, connection, datasource, stage, … (12 groups) |
| Zoho Apptics (extended) | apptics | 16 | project, crash, event, screen, device |
| Zoho IoT (extended) | iot | 78 | product, product-gallery, device, asset, location, record, … (12 groups) |
| Zoho Office Integrator (extended) | officeintegrator | 49 | document, template, fillable, pdf, spreadsheet, presentation, … (7 groups) |
| Zoho PDF Editor (extended) | pdfeditor | 52 | document, image, page, pagenumber, watermark, link, … (12 groups) |
| Zoho Show (extended) | show | 65 | presentation, member, publish, workspace, theme, slide, … (15 groups) |
| Zoho Vani (extended) | vani | 171 | edition, subscription, template, team, team-member, team-request, … (33 groups) |
| Zoho Vertical Studio (extended) | vertical | 343 | org, user, record, subform, lead, inventory, … (59 groups) |
Not addable, because Zoho publishes no API for them: Forms, Sites, Flow (no management API), Notebook, TeamInbox, RouteIQ, CommandCenter, LandingPage, CommunitySpaces. Reach their data through the products that do have one (Creator, Analytics, CRM).
A few services sit on hosts outside *.zoho.<dc>: POS is the former Zakya (api.zakya.com|in), Vani is api.app.vanihq.<dc>, Office Integrator is api.office-integrator.<dc>. All are on zone's host allow-list, so a token or key is never sent anywhere else. Office Integrator has no OAuth at all — it authenticates with an API key you store once: zone ctx officeintegrator apikey=<key> (and dc=eu if your account is not on .com); zone login officeintegrator tells you the same.
Beyond REST rows, a few commands carry real logic: zone crm pull snapshots an org's metadata (modules, fields, picklists, layouts, Deluge functions) to disk; zone books pull and zone inventory pull walk every organization's settings into a folder each; zone crm fn push/pull/test/invoke and zone crm fmt form a Deluge toolchain; zone transcribe runs Whisper locally on meeting recordings; zone zet wraps Zoho's Marketplace widget toolkit; zone bug files a bug report without a GitHub account. Each has --help with examples.
Authentication
zone login [services...]— one browser consent for the named services;--allfor every core service;--dc eu(orin,com.au,jp,uk,ca,sa,ae,sg,cn) for another datacenter;--no-browserprints the consent URL for headless machines. Omit--dcin a terminal to be prompted.- Scopes are minimized before the consent URL is built (a broader scope in the same list implies the narrower ones), and a request too long for one URL is split into consent rounds.
--raw-scopesandZONE_CONSENT_BUDGETadjust that. - Zoho keeps 20 refresh tokens per client per user and silently invalidates the rest, so grants no service points at are revoked after each login;
zone grantslists them,zone grants --prunecleans up by hand,--no-pruneopts out. zone status [--live]shows auth state per service;--liveprobes a real read-only endpoint each.zone token <service>prints a valid access token for scripts.zone logout [services...]removes sessions.- The default OAuth client is shared. Bring your own with
--client-id/--client-secretorZONE_CLIENT_ID/ZONE_CLIENT_SECRET(redirect URIhttp://localhost:14893/zoho/callback, or your own port with--port). - Session files are mode
0600, one per service, under the storezone statusnames. - API-key products (Office Integrator) have no session:
zone statusreports them asok (api key)oncezone ctx <service> apikey=<key>is stored, and the key rides on every request from context.
Environment variables
| Variable | Purpose |
|---|---|
| ZONE_HOME | Session directory; overrides both the project-local ./.zone and ~/.zone |
| ZONE_CLIENT_ID / ZONE_CLIENT_SECRET | Custom OAuth client |
| ZONE_PORT | OAuth callback port (default 14893) |
| ZONE_TIMEOUT | Per-request timeout in ms (default 60000; 300000 for uploads and downloads) |
| ZONE_RETRIES | How many times a throttled (429) or transient call is retried before exit 7 (default 3; 0 disables) |
| ZONE_RETRY_MAX_WAIT_MS | Longest single wait zone will sit out for a retry (default 30000); a reset further away fails fast with the reset time |
| ZONE_JSON_ERRORS | 1 → the JSON error envelope on stderr's last line, without --json |
| ZONE_POLICY / ZONE_POLICY_DENY | Allow / deny rules, e.g. *:GET — same grammar as --allow / --deny |
| ZONE_AUDIT | Audit log path — same as --audit |
| ZONE_API_VERSION | Pin the Zoho API version (e.g. v8) — same as --api-version |
| ZONE_API_FALLBACK | 0 disables the automatic CRM API-version fallback (v9 → v8 → … → v2 when the default version fails with a version-drift signature) |
| ZONE_CONSENT_BUDGET | Max consent URL length before a login is split into rounds (default 7500) |
| ZONE_BUG_ENDPOINT | Bug relay for zone bug; unset means nothing is ever sent |
| ZONE_NO_UPDATE_CHECK | 1 → no "newer version" notice (NO_UPDATE_NOTIFIER and CI=true also) |
| NO_COLOR / DEBUG | Disable colours / true prints error details |
Troubleshooting
zone status --liveis the fastest diagnosis: per service, does the stored grant work right now?- Exit
3— not signed in for that service:zone login <service>. Exit4— the grant lacks a scope:zone login <service>again picks up the current scope set. - Exit
5— Zoho rejected the call. Thezohofield carries Zoho's own body;--verboseprints full details (redacted). CRM names the offending field indetails.param_name, and thehinttranslates the common ones. - "belongs to multiple organizations" — set the org once:
zone ctx <service> organization_id=<id>(discover withzone api <service> GET /organizations). - Git Bash rewrites
/Leadsinto a Windows path. zone detects and undoes it; if you still see a filesystem path in an error, prefix the command withMSYS_NO_PATHCONV=1. - Something looks wrong?
zone bug "<title>" -m "<what happened>"collects versions, platform, the command shape and the structured error, shows you the exact payload and asks before sending anything. It never includes tokens,.zonecontents or request/response bodies, and--dry-run,--printand--outlet you see or save the report without transmitting it.
Development
zone is a thin CLI over four packages, each published on its own and developed in sibling repos:
| Package | Owns |
|---|---|
| @wanasapps/deluge-core | Deluge formatter, signature parser, grammar, snippets — no I/O |
| @wanasapps/zoho-auth | OAuth, datacenters, the session store |
| @wanasapps/zoho-api | Service registry and the REST client, including the Zoho host allow-list |
| @wanasapps/zcrm-core | CRM services and the metadata extractor behind zone crm pull |
npm install && npm test # offline suite, no sessions needed
npm run relink # re-point @wanasapps deps at sibling working copies (any npm install replaces the links)
npm run gen:commands # regenerate docs/COMMANDS.md from the specs
npm run gen:docs # regenerate docs/zone-commands.html
npm run publish:all -- --dry-run # plan a bottom-up publish of every package that is ahead of npmWhere commands come from. Each service's commands are declarative rows (method, path, args, flags, notes) that src/core/commandSpec.js turns into zone <service> <group> <name>:
| Location | Holds |
|---|---|
| src/specs/<service>.js (or src/specs/crm/, src/specs/desk/) | hand-written rows, checked against live orgs |
| src/specs/oas-extras/<service>.js | rows generated from Zoho's own OpenAPI specs for operations the hand-written file lacks — merged automatically by the loader; every row's notes name its source file and operationId, and say whether a live call has confirmed it |
| src/specs/finance-shared/ | resources Books and Inventory serve identically (purchase returns, item masters and variants, categories), loaded by both |
| src/core/guides/<service>.md | the hand-written part of each service's skill: payload shapes and traps |
Coverage is audited against Zoho's published definitions where they exist — openapi-all.zip bundles on zoho.com, the zoho/*-oas repos on GitHub, and CRM's runtime GET /crm/<v>/__apis registry (scripts/discover-crm-apis.js). src/core/specValidate.js rejects a row whose path placeholder is neither a declared arg nor a known context key.
prepublishOnly runs scripts/check-publish.js (shebang line endings, shipped files, lockfile versions inside their ranges, every @wanasapps range resolving on npm) and then the suite. The history of what changed in each release is in CHANGELOG.md.
Library use is possible but secondary:
const zone = require('wanas-zone-cli');
const org = await zone.api.request('crm', 'GET', '/org');Support
- Issues: github.com/Wanas-Apps/wanas-zone-cli/issues — or
zone bugfrom the terminal - Email: [email protected]
- Website: www.wanasapps.com
Wanas Apps is a Zoho Premium Partner and technical consulting firm in Ras al-Khaimah and Cairo, building Zoho implementations, Catalyst applications and integrations for the MENA region. zone is the tool we use to do that work.
