agentleFS
andmariosandmarios/zendesk-skill/CLAUDE.md

zendesk-skill

CLAUDE.md8 starsChanged 20 days agoMITView on GitHub

A Claude Code skill that provides a CLI for Zendesk Support integration.

  • In this repositoryOne other file it gives its agents.

The file

We split this CLAUDE.md into the rules it gives an agent

7 rules. About 0 are common, 1 is distinctive, and 6 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 6

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Add command function in cli.py with @app.command() decorator

    line 117
  2. Very specific:

    Use Typer's Annotated type hints for parameters

    line 118
  3. Very specific:

    Call get_client() to get the Zendesk client

    line 119
  4. Very specific:

    Use run_async() to call async client methods

    line 120
  5. Very specific:

    Add named queries in queries.py if appropriate

    line 123
  6. Very specific:

    Update SKILL.md with command documentation

    line 124
  7. Distinctive:

    All commands output JSON to stdout:

    line 200

≈ “Common” is an estimate: at least 1 in 5 of the 26,980 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
CLAUDE.md

Zendesk CLI - Developer Guide

A Claude Code skill that provides a CLI for Zendesk Support integration.

Project Structure

zendesk-skill/
├── pyproject.toml           # uv project config (entry point: zd-cli)
├── SKILL.md                 # Claude Code skill file
├── CLAUDE.md                # This file
├── README.md                # User documentation
├── reference/               # Additional documentation
│   └── search-syntax.md     # Zendesk search query reference
├── src/
│   └── zendesk_skill/
│       ├── __init__.py      # Package init with key re-exports
│       ├── cli.py           # Typer CLI with commands
│       ├── client.py        # Zendesk API client (httpx-based) + secrets management
│       ├── crypto.py        # Fernet encryption at rest (machine-derived key, HKDF)
│       ├── enrich.py        # People / custom field name resolution
│       ├── export.py        # Render a whole ticket as Markdown/HTML
│       ├── formatting.py    # Markdown-to-HTML for write operations
│       ├── operations.py    # Shared business logic (CLI + MCP server)
│       ├── reporting.py     # Slack & Markdown report generation
│       ├── server.py        # MCP server implementation
│       ├── storage.py       # Response storage + structure extraction
│       ├── queries.py       # jq query definitions
│       ├── utils/           # Shared utilities
│       │   ├── __init__.py
│       │   ├── time.py      # Time formatting (mins_to_human)
│       │   └── security.py  # Field wrapping for security
│       ├── scripts/         # Standalone analysis scripts
│       │   └── analyze_support_metrics.py
│       └── auth/            # Pluggable auth backends
│           ├── __init__.py  # Package exports
│           ├── provider.py  # AuthProvider protocol + resolve factory
│           ├── token_auth.py # Basic Auth (email + API token)
│           ├── oauth.py     # OAuth 2.0 Authorization Code + PKCE
│           ├── server.py    # Server-side OAuth token management
│           └── scopes.py    # OAuth scope constants
└── tests/
    ├── test_basic.py        # Basic + formatting tests
    └── test_auth.py         # Auth package tests

Architecture

CLI (cli.py)

  • Uses Typer for command-line interface
  • 25 commands organized by category
  • Outputs JSON to stdout
  • Saves full responses to /tmp/zd-cli-$UID/

Auth (auth/)

  • AuthProvider protocol: pluggable auth backends
  • resolve_auth_provider() factory: OAuth token → API token → error
  • TokenAuthProvider: Basic Auth with email + API token
  • OAuthProvider: OAuth 2.0 Authorization Code + PKCE, auto-refresh
  • Lazy imports in provider.py to avoid circular deps with client.py

API Client (client.py)

  • httpx-based async HTTP client
  • Delegates auth to AuthProvider (accepts auth_provider param)
  • Backwards compatible: still accepts explicit email/token/subdomain
  • Proper error handling with actionable messages

Storage (storage.py)

  • Saves all API responses to /tmp/zd-cli-$UID/
  • Auto-extracts response structure for metadata
  • File naming: {command}_{sha256_8}_{timestamp}.json

Queries (queries.py)

  • Named jq queries per command type
  • Executes jq via subprocess (safe)
  • Supports both named and custom queries

Command Categories

  1. Ticket Commands (6): search, ticket, ticket-details, export-ticket, linked-incidents, attachment
  2. Write Operations (4): update-ticket, create-ticket, add-note, add-comment
  3. Metrics & Analytics (4): ticket-metrics, list-metrics, satisfaction-ratings, satisfaction-rating
  4. Views (3): views, view-count, view-tickets
  5. Users & Orgs (4): user, search-users, org, search-orgs
  6. Config (4): groups, tags, sla-policies, me
  7. Query (1): query (for jq queries on stored files)

Development

Running Commands

# Show all commands
uv run zd-cli --help

# Run specific command
uv run zd-cli me
uv run zd-cli search "status:open"
uv run zd-cli ticket-details 12345

# Get command help
uv run zd-cli search --help

Testing

# Run all tests
uv run pytest -v

# Test CLI import
uv run python -c "from zendesk_skill.cli import app; print('OK')"

Adding a New Command

  1. Add command function in cli.py with @app.command() decorator
  2. Use Typer's Annotated type hints for parameters
  3. Call get_client() to get the Zendesk client
  4. Use run_async() to call async client methods
  5. Save response with save_response()
  6. Output summary JSON with output_json()
  7. Add named queries in queries.py if appropriate
  8. Update SKILL.md with command documentation

Command Pattern

@app.command("command-name")
def command_name(
    arg: Annotated[str, typer.Argument(help="Description")],
    option: Annotated[Optional[str], typer.Option("--option", "-o", help="Description")] = None,
    output_path: Annotated[Optional[str], typer.Option("--output", help="Custom output path")] = None,
) -> None:
    """Command description."""
    client = get_client()

    try:
        result = run_async(client.get("endpoint"))
        file_path = save_response("command_name", {"arg": arg}, result, output_path)
        output_json({
            "summary_field": result.get("field"),
            "file_path": str(file_path),
        })
    except ZendeskClientError as e:
        output_error(str(e))

Dependencies

  • typer>=0.9.0 - CLI framework
  • rich>=13.0.0 - Pretty terminal output
  • httpx>=0.27.0 - Async HTTP client
  • pydantic>=2.0.0 - Input validation
  • mistune>=3.0.0 - Markdown-to-HTML conversion for write operations
  • cryptography>=42.0.0 - Fernet encryption for secrets at rest

External Requirements

  • jq must be installed for zd-cli query command to work
  • Zendesk credentials: OAuth token or API token (email + token + subdomain)

Auth Configuration

Auth provider is resolved automatically (first match wins):

  1. OAuth token on disk (~/.config/zd-cli/oauth_token.json.enc) → OAuthProvider
  2. API token (env vars or encrypted secrets) → TokenAuthProvider

API token credentials load from:

  1. Environment variables: ZENDESK_EMAIL, ZENDESK_TOKEN, ZENDESK_SUBDOMAIN
  2. Config file (config.json) for email/subdomain + encrypted secrets (secrets.json.enc) for token

OAuth client credentials load from:

  1. Environment variables: ZENDESK_OAUTH_CLIENT_ID, ZENDESK_OAUTH_CLIENT_SECRET
  2. Encrypted secrets file (secrets.json.enc), managed via zd-cli auth set-oauth-client

Encryption at Rest

Secret files (API tokens, OAuth tokens, client secrets) are encrypted using Fernet symmetric encryption. The key is derived at runtime from machine-specific identifiers and never stored on disk.

  • Module: src/zendesk_skill/crypto.py
  • Key derivation: machine_id + username + app_id → HKDF-SHA256 → Fernet key
  • File convention: foo.json → encrypted as foo.json.enc
  • Auto-migration: plaintext secrets in config.json are auto-migrated to secrets.json.enc on first access
  • Opt-out: Set ZD_ENCRYPTION=none to disable encryption entirely
  • Salt: Auto-generated, stored in config.json (plaintext config stays unencrypted)

Storage layout:

  • config.json — plaintext: email, subdomain, encryption_salt, channel, auth mode settings
  • secrets.json.enc — encrypted: token, oauth_client_id, oauth_client_secret, slack_webhook_url
  • oauth_token.json.enc — encrypted: OAuth access/refresh tokens
  • server_token.json.enc — encrypted: relay server JWT

CLI commands for managing encrypted credentials:

  • zd-cli auth set-oauth-client - Save OAuth client_id and client_secret (encrypted)
  • zd-cli auth login - Save API token credentials (token encrypted, email/subdomain in config)

Response Format

All commands output JSON to stdout:

{
  "summary_field": "value",
  "file_path": "/tmp/zd-cli-$UID/command_xxx.json"
}

The file_path points to the full saved response for follow-up queries.

MCP Server Backup

The original MCP server implementation is preserved in backup-mcp/server.py in case it's needed in the future. The CLI approach was chosen for easier integration with Claude Code skills (no settings.json configuration required).

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.