Egnyte Agentic CLI
The Egnyte Agentic CLI (@egnyte/agentic-cli) is a command-line tool for interacting with the Egnyte API from terminals, CI pipelines, and AI coding agents. It produces JSON-only output, exposes self-describing schema introspection, and enforces --dry-run confirmation before any mutating operation.
Note: This tool is designed for two primary audiences: AI agents (Claude Code, Cursor, Copilot Workspace) that need structured, machine-readable output; and developers automating Egnyte workflows from scripts or CI pipelines.
Installation
Requirements: Node.js ≥ 14, npm ≥ 6
npm install -g @egnyte/agentic-cli
To upgrade to the latest version:
npm install -g @egnyte/agentic-cli@latest
Verify the installation:
egnyte --help
egnyte schema --list
Authentication
Option A — Interactive Login (Recommended for Local Use)
The CLI ships with a built-in OAuth app — no app registration required. Only --domain is needed:
egnyte login --domain https://mycompany.egnyte.com
The CLI opens your browser for OAuth authorization. After approving, copy the code= value from the redirect URL and paste it in the terminal. The access token is stored at ~/.config/egnyte-cli/config.json with file mode 0600 (owner read/write only).
Using your own OAuth app (optional — for custom redirect URIs, restricted scopes, or enterprise app policies):
egnyte login \
--domain https://mycompany.egnyte.com \
--client-id YOUR_CLIENT_ID \
--client-secret YOUR_CLIENT_SECRET
# Equivalent via env vars
EGNYTE_DOMAIN=https://mycompany.egnyte.com \
EGNYTE_CLIENT_ID=YOUR_CLIENT_ID \
EGNYTE_CLIENT_SECRET=YOUR_CLIENT_SECRET \
egnyte login
Register your own app at developers.egnyte.com if needed.
Option B — Environment Variables (CI / Headless / AI Agents)
Set EGNYTE_TOKEN and EGNYTE_DOMAIN to bypass stored credentials entirely:
export EGNYTE_TOKEN=<bearer-token>
export EGNYTE_DOMAIN=https://mycompany.egnyte.com
Additional login-time variables:
| Variable | Description |
|---|---|
EGNYTE_CLIENT_ID | OAuth application client ID |
EGNYTE_CLIENT_SECRET | OAuth application client secret |
EGNYTE_SCOPE | Space-separated scopes (omit for all scopes) |
EGNYTE_REDIRECT_URI | Redirect URI (default: https://www.egnyte.com) |
Auth Precedence
--token / --domain flags
↓
EGNYTE_TOKEN / EGNYTE_DOMAIN env vars
↓
stored profile (~/.config/egnyte-cli/config.json)
Named Profiles
Use named profiles to manage multiple domains:
# Log in to staging and production as separate profiles
egnyte login --domain https://mycompany-staging.egnyte.com --client-id <id> --client-secret <s> --profile staging
egnyte login --domain https://mycompany.egnyte.com --client-id <id> --client-secret <s> --profile prod
# Restrict scopes for a profile
egnyte login --domain https://mycompany.egnyte.com --client-id <id> --client-secret <s> \
--scope "Egnyte.filesystem Egnyte.user" --profile prod-readonly
# Switch the active profile
egnyte profiles use staging
# List all profiles
egnyte profiles list
# Remove a profile
egnyte profiles remove staging
Token Auto-Refresh
If a stored token is within 5 minutes of expiry and a refresh_token is present, the CLI silently refreshes it before executing the request.
Global Flags
Every command accepts the following flags:
| Flag | Description |
|---|---|
--json '{}' | JSON request body or query parameters |
--fields a,b,c | Return only specified fields (reduces response size and AI token cost) |
--dry-run | Print the equivalent curl command; do not execute |
--yes | Execute a mutating command without a confirmation prompt |
--bulk-file-path <csv> | Execute a command in bulk from a CSV file |
--from-csv <csv> | Alias for --bulk-file-path |
--parallelism <n> | Max concurrent bulk operations (default: 2) |
--progress | Human-readable progress updates on stderr |
--json-progress | Newline-delimited JSON progress events on stderr |
--profile <name> | Use a named profile instead of the default |
--token / --domain | Override stored credentials for a single call |
Schema Discovery
Inspect available operations and their parameters at runtime — no external documentation required.
# List all available operations
egnyte schema --list
# Full parameter reference for a specific operation
egnyte schema fs.action
egnyte schema users.create
egnyte schema search.advanced
egnyte schema ai.ask-kb
Example output:
{
"summary": "Perform a file/folder operation: add_folder | move | copy | rename",
"method": "POST",
"endpoint": "/pubapi/v1/fs/{path}",
"mutating": true,
"body_params": {
"action": { "type": "string", "required": true, "description": "add_folder | move | copy | rename" },
"destination": { "type": "string", "required": false, "description": "Destination path (required for move and copy)" },
"new_name": { "type": "string", "required": false, "description": "New filename (required for rename)" }
},
"example": "egnyte fs action /Shared/NewFolder --json '{\"action\": \"add_folder\"}' --dry-run"
}
Commands
All commands write JSON to stdout. Errors are written as {"error":"..."} to stderr. Exit code is 0 on success, 1 on error.
File System
Get File or Folder Metadata
egnyte fs get <path> [--json '{}'] [--fields a,b,c]
| Parameter | Type | Required | Description |
|---|---|---|---|
path | string | Yes | Absolute path to the file or folder (must start with /) |
list_content | boolean | No | Set true to list folder contents |
count | integer | No | Items per page (for pagination) |
offset | integer | No | Pagination offset |
Example — file metadata:
egnyte fs get /Shared/report.pdf --fields name,path,size,entry_id
Example — list folder contents with pagination:
egnyte fs get /Shared \
--json '{"list_content": true, "count": 50, "offset": 0}' \
--fields files.name,files.path,files.size,folders.name,folders.path,folders.is_folder
Folder and File Actions
Named subcommands (preferred):
# Create a folder
egnyte fs mkdir /Shared/NewFolder --dry-run
egnyte fs mkdir /Shared/NewFolder --yes
# Rename a file or folder
egnyte fs rename /Shared/report.pdf --name report-final.pdf --yes
# Move a file or folder
egnyte fs move /Shared/report.pdf --to /Shared/Archive/report.pdf --yes
# Copy a file or folder
egnyte fs copy /Shared/report.pdf --to /Shared/Backup/report.pdf --yes
Always run with --dry-run first to preview the equivalent curl command before executing.
Upload
# Standard upload — recommended for files ≤ 10 MB
egnyte fs upload /Shared/docs/report.pdf --file ./report.pdf --yes
# Chunked upload — recommended for files > 10 MB
# Minimum chunk size enforced by the API: 10 MB (except for the final chunk)
egnyte fs upload-chunked /Shared/bigfile.iso --file ./bigfile.iso --yes
# Custom chunk size in bytes (must be ≥ 10485760 for non-final chunks)
egnyte fs upload-chunked /Shared/bigfile.iso --file ./bigfile.iso --chunk-size 15728640 --yes
Files smaller than one chunk size automatically fall back to the standard /fs-content endpoint.
Download
Downloads stream directly to disk and are safe for files of any size.
# Download by path
egnyte fs download /Shared/report.pdf --out ./report.pdf
# Download by group_id
egnyte fs download-by-id <group-id> --out ./report.pdf
# Resume an interrupted download
egnyte fs download-by-id <group-id> --out ./report.pdf --resume
Delete
egnyte fs delete /Shared/old-report.pdf --dry-run
egnyte fs delete /Shared/old-report.pdf --yes
Read File Content as Text
Fetch file content as text without writing to disk — useful for reading documents or CSVs in an agent workflow.
egnyte fs get-content /Shared/notes.txt
egnyte fs get-content /Shared/data.csv --json '{"offset":0,"limit":10000}'
Custom Metadata
# List all metadata namespaces and their field definitions
egnyte fs list-metadata-namespaces --fields namespace,fields
# Set custom metadata on a file
egnyte fs set-metadata /Shared/contract.pdf \
--json '{"namespace":"contract","values":{"status":"signed","reviewed_by":"jsmith"}}' \
--dry-run
egnyte fs set-metadata /Shared/contract.pdf \
--json '{"namespace":"contract","values":{"status":"signed","reviewed_by":"jsmith"}}' \
--yes
Search
Basic Full-Text Search
egnyte search <query> [--json '{}'] [--fields a,b,c]
# Basic search
egnyte search "quarterly report" --fields results.name,results.path,results.size
# Scoped to a folder with pagination
egnyte search "budget" \
--json '{"count": 20, "offset": 0, "folder": "/Shared/Finance", "type": "file"}' \
--fields results.name,results.path,results.size
Advanced Search
egnyte search advanced <query> [--json '{}'] [--fields a,b,c]
# Filter by modification date
egnyte search advanced "contract" \
--json '{"folder":"/Shared/Legal","modified_after":"2024-01-01","type":"file"}' \
--fields results.name,results.path,results.size
# Filter by custom metadata
egnyte search advanced "NDA" \
--json '{"custom_metadata":{"status":"signed"},"namespaces":["contract"]}' \
--fields results.name,results.path
AI
All AI commands are read-only — --yes is not required.
Ask a Question
egnyte ai ask "<question>" [--json '{}'] [--fields a,b,c]
# General Copilot question
egnyte ai ask "What are the key metrics in Q3?" --fields response
# Scoped to specific folders with citations
egnyte ai ask "Revenue trends?" \
--json '{"selectedItems":{"folders":[{"id":"<folder-id>"}]},"includeCitations":true}' \
--fields response,citations
Ask About a Specific File
Path is automatically resolved to an entry-id.
egnyte ai ask-document /Shared/Contracts/acme.pdf "What are the payment terms?" --fields response
egnyte ai ask-document /Shared/Contracts/acme.pdf "What are the payment terms?" \
--json '{"includeCitations":true}' --fields response,citations
Summarize a File
egnyte ai summarize /Shared/Reports/annual-report.pdf --fields response
Knowledge Bases
# List active Knowledge Bases
egnyte ai list-kbs \
--json '{"status":["ACTIVE"],"sortBy":["name"],"sortDirection":["ASC"]}' \
--fields content
# Query a Knowledge Base with citations
egnyte ai ask-kb kb-abc123 "What is the refund policy?" \
--json '{"includeCitations":true}' \
--fields response,citations
Hybrid Search
Combines semantic and keyword matching. semanticWeight ranges from 0.0 (pure keyword) to 1.0 (pure semantic).
egnyte ai hybrid-search "quarterly report" \
--json '{"semanticWeight":0.7,"folderPath":"/Shared/Finance","limit":10}' \
--fields results
Agents
Use agents instead of ai ask when you need multi-turn conversation continuity, custom instructions, or complex workflows.
agents ask is synchronous by default — it polls until the agent responds (up to 5 minutes). Use --no-wait to fire-and-forget.
All agent commands are read-only — --yes is not required.
Response status values: PENDING | RUNNING | COMPLETED | FAILED
# List all available agents
egnyte agents list --fields agentId,name,status,category
# Ask an agent — blocks until complete
egnyte agents ask <agentId> "Summarize the Q3 results" --fields responseText,citations
# Multi-turn: continue a prior conversation
egnyte agents ask <agentId> "Now compare that to Q2" \
--json '{"conversationId":"<id from prior response>"}' \
--fields responseText
# Custom agent behavior for this call
egnyte agents ask <agentId> "Draft a summary" \
--json '{"instructions":"Respond in bullet points, no more than 5 items"}' \
--fields responseText
# Scope to specific files
egnyte agents ask <agentId> "What are the key risks?" \
--json '{"selectedItems":{"files":[{"entryId":"<id>","filePath":"/Shared/contract.pdf"}]}}' \
--fields responseText,citations
# Fire-and-forget — returns requestId and conversationId immediately
egnyte agents ask <agentId> "Long running analysis task" \
--no-wait --fields requestId,conversationId
# Check status later
egnyte agents status <agentId> <requestId> --fields status,responseText,citations
Links
accessibility values: anyone | domain | password | recipients
# Create a shared link
egnyte links create \
--json '{"path":"/Shared/report.pdf","type":"file","accessibility":"domain"}' \
--dry-run
egnyte links create \
--json '{"path":"/Shared/report.pdf","type":"file","accessibility":"anyone","expiry_date":"2026-12-31"}' \
--fields id,url,path,accessibility --yes
# List links for a path
egnyte links list --json '{"path":"/Shared/report.pdf"}' --fields ids,total_count
# Get a specific link
egnyte links get <link-id> --fields id,url,path,accessibility
# Delete a link
egnyte links delete <link-id> --dry-run
egnyte links delete <link-id> --yes
Users
Uses the SCIM-compatible /pubapi/v2/users endpoint.
# List users
egnyte users list --json '{"count": 50}' --fields resources.id,resources.userName,resources.email,resources.active
# Get a user by numeric ID
egnyte users get <id> --fields userName,email,active,userType
# Create a user
egnyte users create \
--json '{"userName":"jsmith@co.com","email":{"value":"jsmith@co.com"},"active":true,"sendInvite":false}' \
--dry-run
egnyte users create \
--json '{"userName":"jsmith@co.com","email":{"value":"jsmith@co.com"},"active":true,"sendInvite":false}' \
--yes
# Update a user — PATCH, only fields you include are changed
egnyte users update <id> --json '{"active": false}' --yes
# Delete a user
egnyte users delete <id> --dry-run
egnyte users delete <id> --yes
Groups
Uses the SCIM-compatible /pubapi/v2/groups endpoint.
# List groups
egnyte groups list --json '{"count": 50}' --fields resources.id,resources.displayName
# Get a group by ID
egnyte groups get <id> --fields displayName,members
# Create a group
egnyte groups create --json '{"displayName":"Engineering"}' --yes
# Update a group
egnyte groups update <id> --json '{"displayName":"Eng Team"}' --yes
# Delete a group
egnyte groups delete <id> --dry-run
egnyte groups delete <id> --yes
Permissions
Folder permission levels: Owner | Editor | Viewer | None
# Get user permissions on a folder
egnyte perms get-user /Shared/Finance --fields users
# Set user permissions
egnyte perms set-user /Shared/Finance \
--json '{"users": {"jsmith": "Viewer", "mjones": "Editor"}}' \
--yes
# Remove user permissions
egnyte perms delete-user /Shared/Finance --json '{"users": ["jsmith"]}' --yes
# Get group permissions on a folder
egnyte perms get-group /Shared/Finance --fields groups
# Set group permissions
egnyte perms set-group /Shared/Finance \
--json '{"groups": {"Engineering": "Editor"}}' \
--yes
# Remove group permissions
egnyte perms delete-group /Shared/Finance --json '{"groups": ["Engineering"]}' --yes
# Get a specific user's permission level
egnyte perms get-by-user jsmith --json '{"folder": "/Shared/Finance"}'
Events
Pull the audit trail for file and folder activity across the domain.
Event types: create | move | delete | edit | lock | unlock | restore
# Step 1 — get the latest event ID (your polling start point)
egnyte events get-cursor
# Step 2 — list events from that ID
egnyte events list --json '{"id": 12345678, "count": 20}' \
--fields events.id,events.action,events.actor,events.timestamp
# Filter by folder and event type
egnyte events list \
--json '{"id": 12345678, "count": 50, "folder": "/Shared", "type": "create|move|delete"}' \
--fields events.id,events.action,events.actor,events.timestamp,events.data
Notes
Comments attached to files.
# Add a note
egnyte notes add /Shared/report.pdf \
--json '{"body": "Please review section 3 before the Thursday call"}' \
--dry-run
egnyte notes add /Shared/report.pdf \
--json '{"body": "Please review section 3 before the Thursday call"}'
# List all notes on a file
egnyte notes list /Shared/report.pdf
# Get a note by ID
egnyte notes get <note-id>
# Delete a note
egnyte notes delete <note-id> --dry-run
egnyte notes delete <note-id>
File Locking
Prevent concurrent edits by locking a file.
# Lock a file
egnyte lock lock /Shared/report.pdf \
--json '{"lock_token": "my-token", "lock_timeout": 300}'
# Check lock status
egnyte lock get /Shared/report.pdf --fields locked,lock_owner,lock_timeout
# Unlock a file
egnyte lock unlock /Shared/report.pdf --json '{"lock_token": "my-token"}'
Trash
# List items in the trash
egnyte trash list --json '{"count": 50}' --fields items.name,items.path,items.size,items.id
# Restore items (requires IDs from trash list)
egnyte trash restore --json '{"ids": ["item_id_1", "item_id_2"]}' --dry-run
egnyte trash restore --json '{"ids": ["item_id_1"]}' --yes
# Permanently delete items from the trash
egnyte trash delete --json '{"ids": ["item_id_1"]}' --dry-run
egnyte trash delete --json '{"ids": ["item_id_1"]}' --yes
Projects
Manage lifecycle and metadata for project folders.
# List all project folders
egnyte projects list --fields name,id,status
# Get details for a specific project
egnyte projects get <project-id> --fields name,status
# Create a project from a template (v2 API)
egnyte projects create \
--json '{"name":"New HQ","status":"pending","parentFolderId":"...","templateFolderId":"...","folderName":"New HQ Folder"}' \
--yes
# Mark an existing folder as a project (v1 API)
egnyte projects create \
--json '{"name":"Existing Site","status":"in-progress","rootFolderId":"..."}' \
--yes
# Update project metadata
egnyte projects update <project-id> --json '{"status": "completed"}' --yes
# Delete project metadata (reverts the folder to normal)
egnyte projects delete <project-id> --yes
User Info
Returns the authenticated user's live profile from the API, validating that the stored token is still accepted.
egnyte userinfo
egnyte userinfo --fields username,email,user_type
Note: Unlike egnyte whoami (which reads stored credential metadata without a network call), userinfo makes a live API request to verify the token.
Bulk Operations
For supported mutating commands, pass a CSV file to run one API call per row.
# delete.csv format:
# path
# /Shared/old-a.pdf
# /Shared/old-b.pdf
# Preview first
egnyte fs delete --bulk-file-path ./delete.csv --dry-run
# Execute with concurrency and progress reporting
egnyte fs delete --bulk-file-path ./delete.csv --parallelism 4 --progress --yes
Upload in bulk:
egnyte fs upload --bulk-file-path ./uploads.csv --parallelism 4 --progress --yes
Rate Limiting and Retries
On 429 Too Many Requests, the CLI retries up to 3 times, honoring the Retry-After header when present and falling back to exponential backoff (1 s → 2 s → 4 s).
On 5xx server errors, the CLI retries GET and HEAD requests up to 3 times with exponential backoff and jitter. POST, PUT, and DELETE requests fail immediately to avoid duplicate mutations.
Using with Claude Code
Setup
npm install -g @egnyte/agentic-cli
# Authenticate — built-in OAuth app, no registration needed
egnyte login --domain https://mycompany.egnyte.com
# Add the skill file to Claude's global instructions
cat CLAUDE.md >> ~/.claude/CLAUDE.md
The CLAUDE.md file teaches Claude the core operating rules: always --dry-run before mutations, always --fields on list calls, never guess file IDs, and paths must start with /.
Example Prompts
Read operations — Claude executes immediately:
What files are in /Shared/Finance?
How many PDFs are in /Shared/Projects? Show names and sizes only.
Search for "quarterly report" in /Shared.
Mutations — Claude dry-runs, shows the curl output, then asks for confirmation:
Create a folder called /Shared/2026-Archive.
Upload ./report.pdf to /Shared/Finance.
Move everything in /Shared/Inbox to /Shared/Processed.
Delete /Shared/Temp.
Multi-step tasks:
Create /Shared/Archive/Q1-2026, upload all PDFs from ./exports into it, then list what was uploaded.
Dry-Run Confirmation Flow
When you ask Claude to delete a file, it will:
- Run
egnyte fs delete /Shared/report.pdf --dry-run - Display the exact
curlcommand with the token masked as*** - Ask for your confirmation before executing
curl -X DELETE 'https://mycompany.egnyte.com/pubapi/v1/fs/Shared/report.pdf' \
-H 'Authorization: ***'
Ready to delete /Shared/report.pdf. Confirm?
Security
Credential Storage
Tokens are stored at ~/.config/egnyte-cli/config.json with file mode 0600 (owner read/write only). The file contains: access_token, refresh_token, client_id, client_secret, domain, and expires_at.
To remove stored credentials:
egnyte logout # removes the default profile
egnyte profiles remove <name> # removes a named profile
rm ~/.config/egnyte-cli/config.json # removes all profiles
Path Validation
Every path argument is validated against the following rules before any network call:
| Rule | Example Blocked Input |
|---|---|
Must start with / | Shared/docs |
No path traversal (..) | /Shared/../../etc/passwd |
| No pre-encoded slash | /Shared%2Fdocs |
| No double-encoded characters | /Shared%252F |
| No embedded query string | /Shared?foo=bar |
| No null byte | /Shared%00docs |
$ egnyte fs get /Shared/../../etc/passwd
{"error":"Invalid path — path traversal (..) detected"}
Error Codes
| Status | Description | Resolution |
|---|---|---|
400 | Malformed request body or invalid parameter value | Check the parameter table for the command using egnyte schema <operation> |
401 | Invalid or expired token | Run egnyte login to re-authenticate, or check that EGNYTE_TOKEN is set correctly |
403 | Insufficient permissions | Verify the authenticated user has the required folder access |
404 | File, folder, or resource not found | Confirm the path exists with egnyte fs get <path> |
429 | Too many requests | The CLI retries automatically; if persistent, reduce --parallelism in bulk operations |
5xx | Server error | GET/HEAD requests retry automatically; POST/PUT/DELETE fail immediately |
Related Resources
- Egnyte Developer Portal — Full API documentation; register a custom OAuth app if needed
- Getting Started Guide — Obtain credentials and understand API basics
- GitHub Issues — Report bugs and request features
