Skill: niyol/clickup-ticket-manager (version 0.2.0)

--- name: clup description: ClickUp Ticket Manager. Create tasks in ClickUp with quality descriptions (2-3 sentences minimum). --- # ClickUp Ticket Manager **CLI tool: `clup.sh` (or `clup` if symlinked)** **Prerequisites:** - Script must be executable: `chmod +x clup.sh` - Required ENV variables: `CLICKUP_API_KEY`, `CLICKUP_DEFAULT_LIST_ID` - Optional: Create symlink for system-wide access ## When to Use User says: - "Create a ticket for..." - "Make a task for..." - "I need a reminder for..." - "Add a ClickUp ticket for..." ## Your Job **Transform vague input into quality tickets with context!** ### Quality Rules 1. **Title:** Short, clear, actionable 2. **Description:** MINIMUM 2-3 sentences with: - **What** needs to be done? - **Why** / **What for**? - **Context** (system, server, user, etc.) 3. **If input is vague:** ASK before creating! ### Example Transformation ❌ **User:** "ticket for firewall rule" ✅ **You create:** ```bash ./clup.sh --title "Firewall Rule for Production System" \ --description "Open port 443 from server web-01 (10.0.1.5) to db-prod (10.0.2.10). Required for API communication after migration. Coordination with network team needed." ``` ## Command ```bash # Basic (use ./clup.sh or clup depending on installation) ./clup.sh --title "..." --description "..." # With priority ./clup.sh --title "..." --description "..." --priority high # Priority: urgent, high, normal, low (optional) # With custom tags ./clup.sh --title "..." --description "..." --tags "bug,urgent,backend" # Tags: comma-separated list (optional) ``` **Note:** If installed via symlink, use `clup` instead of `./clup.sh` ## Response After success, show the user the ClickUp URL so they can click through. ## Notes - Default tags are automatically added (configurable via `CLICKUP_DEFAULT_TAG`, comma-separated) - Default status: "BACKLOG" (configurable via `CLICKUP_DEFAULT_STATUS`) - Default list: Set via `CLICKUP_DEFAULT_LIST_ID` - For help/options: `./clup.sh --help`

path: README.md
content: # ClickUp Ticket Manager

**CLI tool: `clup`**

A CLI tool for quickly creating ClickUp tasks with **basic quality standards**.

Prevents "open firewall" tickets without any context and enforces meaningful descriptions.

## Features

✅ **JSON Output:** Clean JSON response for easy parsing  
✅ **Smart Defaults:** Configurable tag, "BACKLOG" status  
✅ **Priority Mapping:** urgent, high, normal, low  
✅ **Simple CLI:** Only title + description required  
✅ **Direct Links:** Get ClickUp task URL immediately

## Installation

**Prerequisites:** ClickUp API Key and List ID

```bash
# Make script executable
cd clickup-ticket-manager
chmod +x clup.sh

# Set ENV variables
echo 'export CLICKUP_API_KEY="pk_your_api_key_here"' >> ~/.zshrc
echo 'export CLICKUP_DEFAULT_LIST_ID="your_list_id_here"' >> ~/.zshrc

# Optional: Change default status (default is BACKLOG)
echo 'export CLICKUP_DEFAULT_STATUS="to do"' >> ~/.zshrc

# Optional: Change default tags (comma-separated list, default is "automated")
echo 'export CLICKUP_DEFAULT_TAG="bot-created,automated"' >> ~/.zshrc

source ~/.zshrc

# Now you can run it:
./clup.sh --title "Test" --description "Testing the tool"

# Optional: Add to PATH for system-wide access
sudo ln -s "$(pwd)/clup.sh" /usr/local/bin/clup
# Then you can use: clup --title "..." --description "..."
```

### Getting ClickUp API Key

1. Go to **ClickUp Settings** → **Apps**
2. Click **Generate** under "API Token"
3. Copy the token (starts with `pk_`)

### Finding List ID

1. Open your ClickUp list in browser
2. URL looks like: `https://app.clickup.com/123456/v/li/901234567`
3. Numbers after `/li/` are your List ID (`901234567`)

## Usage

### Basic Syntax

```bash
./clup.sh --title "Title" --description "Description"

# Or if you created a symlink:
clup --title "Title" --description "Description"
```

### Examples

**Standard Ticket:**
```bash
./clup.sh --title "Firewall Rule for Server XY" \
     --description "Open port 443 from web-01 (10.0.1.5) to db-prod (10.0.2.10). Required for API communication after migration. Coordination with network team needed."
```

**High Priority:**
```bash
./clup.sh --title "Login not working" \
     --description "Login page returns 500 error since 2:30 PM. All users affected. Likely caused by last deployment." \
     --priority high
```

**Urgent (Production Down):**
```bash
./clup.sh --title "Database offline" \
     --description "Production database db-prod not responding. All services offline since 3:45 PM. Immediate action required!" \
     --priority urgent
```

**Low Priority (Nice-to-Have):**
```bash
./clup.sh --title "Improve Dashboard UI" \
     --description "Calendar widget could be larger for better readability. User feedback from meeting. Not a blocker, more of an enhancement." \
     --priority low
```

### Parameters

| Parameter | Required | Description |
|-----------|----------|-------------|
| `--title` | ✅ Yes | Short, clear title |
| `--description` | ✅ Yes | Description with context (min 2-3 sentences!) |
| `--priority` | No | `urgent`, `high`, `normal`, `low` |
| `--status` | No | Status (default: "BACKLOG") |
| `--help` | - | Show help |

### Auto-set Values

- **Tags:** `automated` (default, changeable via `CLICKUP_DEFAULT_TAG`, comma-separated)
- **Status:** `BACKLOG` (default, changeable via `CLICKUP_DEFAULT_STATUS`)
- **Priority:** Not set (ClickUp uses its default unless you specify `--priority`)

## Output

### Success:

```json
{"status":"ok","ticket_id":"abc123xyz","url":"https://app.clickup.com/t/abc123xyz"}
```

### Error:

```json
{"status":"error","http_code":400,"message":"Failed to create ticket"}
```

## Troubleshooting

### "CLICKUP_API_KEY environment variable not set"

Set the ENV variable:
```bash
export CLICKUP_API_KEY="pk_xxx..."
```

Or permanently in `.zshrc`/`.bashrc`:
```bash
echo 'export CLICKUP_API_KEY="pk_xxx..."' >> ~/.zshrc
source ~/.zshrc
```

### "CLICKUP_DEFAULT_LIST_ID environment variable not set"

Find your List ID in the ClickUp URL and set it:
```bash
export CLICKUP_DEFAULT_LIST_ID="123456789"
```

### "Failed to create task (HTTP 401)"

- API Key is invalid or expired
- Generate a new one in ClickUp Settings → Apps

### "Failed to create task (HTTP 404)"

- List ID is wrong
- Check your list URL and copy the ID after `/li/`

### "Invalid priority"

- Only these values allowed: `urgent`, `high`, `normal`, `low`
- Case-insensitive

## Integration with AI Agents

**Workflow:**

1. User → "Create a ticket: open firewall"
2. AI Agent:
   - Asks for details if needed
   - Creates good description (2-3 sentences)
   - Executes `clup` command
3. User gets ClickUp link back

**For agent integration:** Include `SKILL.md` in your agent's context to ensure quality ticket creation.

## Technical Details

- **API:** ClickUp REST API v2
- **Auth:** Bearer Token (API Key)
- **Output:** JSON
- **Dependencies:** `curl`, `bash` (standard on macOS/Linux)

## Pro Tips

💡 **Set aliases:**
```bash
alias ticket='clup'
alias bug='clup --priority high'
```

💡 **Template scripts:**
```bash
# bug.sh
#!/bin/bash
clup --title "$1" --description "$2" --priority high
```

💡 **Use with agent:**
Just say "Create ticket for..." and let the agent ensure quality!

## Roadmap (Ideas for later)

- [ ] Import multiple tickets from JSON/CSV
- [ ] Support custom fields
- [ ] Set assignees
- [ ] Due dates
- [ ] Load templates
- [ ] Jira/Refined integration

---

**ClickUp Ticket Manager** • A simple CLI tool for creating quality tickets


path: clup.sh
content: #!/bin/bash

# ClickUp Ticket Manager (clup)
# Creates tasks in ClickUp with minimum quality standards

set -eo pipefail  # Exit on error, catch pipeline failures (removed -u for better compatibility)

# Color output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

# Default values
PRIORITY=""  # No default - only set if explicitly provided
STATUS="${CLICKUP_DEFAULT_STATUS:-BACKLOG}"  # Use ENV or default to BACKLOG
TAGS="${CLICKUP_DEFAULT_TAG:-KI}"  # Use ENV or default to 'automated' (comma-separated)

# Print usage
usage() {
    cat << EOF
ClickUp Ticket Manager (clup)
Usage: clup --title "..." --description "..." [OPTIONS]

Create a ClickUp task with smart defaults.

Required:
  --title TITLE           Task title (short and clear)
  --description DESC      Task description (2-3 sentences minimum)

Optional:
  --priority LEVEL        Priority: urgent, high, normal, low (if not set, ClickUp default)
  --status STATUS         Status (overrides default)
  --tags TAG1,TAG2,...    Tags (comma-separated, overrides default)
  --help                  Show this help

Environment Variables:
  CLICKUP_API_KEY              ClickUp API token (required)
  CLICKUP_DEFAULT_LIST_ID      Target list ID (required)
  CLICKUP_DEFAULT_STATUS       Default status for new tasks (default: "BACKLOG")
  CLICKUP_DEFAULT_TAG          Default tags, comma-separated (default: "automated")

Examples:
  clup --title "Open firewall port" \\
       --description "Open port 443 from web-01 to db-prod for API communication..."

  clup --title "Fix login bug" \\
       --description "Login page returns 500 error since deployment..." \\
       --priority high --tags "bug,urgent,backend"

EOF
    exit 0
}

# Parse arguments
TITLE=""
DESCRIPTION=""

while [[ $# -gt 0 ]]; do
    case $1 in
        --title)
            TITLE="$2"
            shift 2
            ;;
        --description|--desc)
            DESCRIPTION="$2"
            shift 2
            ;;
        --priority)
            case "$2" in
                urgent) PRIORITY=1 ;;
                high) PRIORITY=2 ;;
                normal) PRIORITY=3 ;;
                low) PRIORITY=4 ;;
                *) echo -e "${RED}Error: Invalid priority. Use: urgent, high, normal, low${NC}" >&2; exit 1 ;;
            esac
            shift 2
            ;;
        --status)
            STATUS="$2"
            shift 2
            ;;
        --tags)
            TAGS="$2"
            shift 2
            ;;
        --help|-h)
            usage
            ;;
        *)
            echo -e "${RED}Error: Unknown option $1${NC}" >&2
            usage
            ;;
    esac
done

# Validate required env vars
if [[ -z "${CLICKUP_API_KEY:-}" ]]; then
    echo -e "${RED}╔════════════════════════════════════════════════════════════════╗${NC}" >&2
    echo -e "${RED}║ Error: CLICKUP_API_KEY environment variable not set           ║${NC}" >&2
    echo -e "${RED}╚════════════════════════════════════════════════════════════════╝${NC}" >&2
    echo "" >&2
    echo -e "${YELLOW}Please set your ClickUp API key:${NC}" >&2
    echo -e "  ${GREEN}export CLICKUP_API_KEY=\"pk_your_api_key_here\"${NC}" >&2
    echo "" >&2
    echo "To make it permanent, add to ~/.zshrc or ~/.bashrc:" >&2
    echo -e "  ${GREEN}echo 'export CLICKUP_API_KEY=\"pk_xxx\"' >> ~/.zshrc${NC}" >&2
    echo "" >&2
    echo "Get your API key: ClickUp Settings → Apps → Generate API Token" >&2
    exit 1
fi

if [[ -z "${CLICKUP_DEFAULT_LIST_ID:-}" ]]; then
    echo -e "${RED}╔════════════════════════════════════════════════════════════════╗${NC}" >&2
    echo -e "${RED}║ Error: CLICKUP_DEFAULT_LIST_ID environment variable not set   ║${NC}" >&2
    echo -e "${RED}╚════════════════════════════════════════════════════════════════╝${NC}" >&2
    echo "" >&2
    echo -e "${YELLOW}Please set your ClickUp List ID:${NC}" >&2
    echo -e "  ${GREEN}export CLICKUP_DEFAULT_LIST_ID=\"123456789\"${NC}" >&2
    echo "" >&2
    echo "To make it permanent, add to ~/.zshrc or ~/.bashrc:" >&2
    echo -e "  ${GREEN}echo 'export CLICKUP_DEFAULT_LIST_ID=\"xxx\"' >> ~/.zshrc${NC}" >&2
    echo "" >&2
    echo "Find your List ID in the ClickUp URL:" >&2
    echo "  https://app.clickup.com/123456/v/li/901234567" >&2
    echo "                                      ^^^^^^^^^^^" >&2
    echo "                                      This is your List ID" >&2
    exit 1
fi

# Validate required arguments
if [[ -z "$TITLE" ]]; then
    echo -e "${RED}Error: --title is required${NC}" >&2
    usage
fi

if [[ -z "$DESCRIPTION" ]]; then
    echo -e "${RED}Error: --description is required${NC}" >&2
    usage
fi

# Build tags array for JSON
# Convert comma-separated string to JSON array: "tag1,tag2" -> ["tag1","tag2"]
if [[ -n "$TAGS" ]]; then
    IFS=',' read -ra TAG_ARRAY <<< "$TAGS"
    TAGS_JSON=$(printf ',"%s"' "${TAG_ARRAY[@]}")
    TAGS_JSON="[${TAGS_JSON:1}]"  # Remove leading comma and wrap in brackets
else
    TAGS_JSON="[]"
fi

# Build JSON payload
JSON_PAYLOAD=$(cat <<EOF
{
  "name": "$TITLE",
  "description": "$DESCRIPTION",
  "status": "$STATUS",
  "tags": $TAGS_JSON
}
EOF
)

# Add priority only if set
if [[ -n "$PRIORITY" ]]; then
    JSON_PAYLOAD=$(echo "$JSON_PAYLOAD" | sed 's/}$/,\n  "priority": '"$PRIORITY"'\n}/')
fi

# Make API request
response=$(curl -s -w "\n%{http_code}" -X POST \
    "https://api.clickup.com/api/v2/list/${CLICKUP_DEFAULT_LIST_ID}/task" \
    -H "Authorization: ${CLICKUP_API_KEY}" \
    -H "Content-Type: application/json" \
    -d "$JSON_PAYLOAD")

# Extract HTTP status code (last line)
http_code=$(echo "$response" | tail -n1)
body=$(echo "$response" | sed '$d')

if [[ "$http_code" == "200" ]]; then
    task_id=$(echo "$body" | grep -o '"id":"[^"]*"' | head -1 | cut -d'"' -f4)
    task_url=$(echo "$body" | grep -o '"url":"[^"]*"' | head -1 | cut -d'"' -f4)
    
    # Output clean JSON
    cat <<EOF
{"status":"ok","ticket_id":"${task_id}","url":"${task_url}"}
EOF
else
    # Output error JSON
    cat <<EOF >&2
{"status":"error","http_code":${http_code},"message":"Failed to create ticket"}
EOF
    exit 1
fi


Security scan verdicts — ClawScan: suspicious | static analysis:  | VirusTotal: clean | SkillSpector: suspicious (HIGH)