agentsclimarketplace

Ishosting manager

Skill ishosting/ishosting-manager/.claude/skills/ishosting-manager

Complete is*hosting infrastructure management via API. Order and configure VPS, Dedicated, Storage, VPN servers with custom hardware. Install OS, control panels, deploy apps and websites. Manage SSH keys, billing, invoices, DNS, and service lifecycle.

Install
npx -y skills add ishosting/ishosting-manager --skill ishosting-manager

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Complete is*hosting infrastructure management via API. Order and configure VPS, Dedicated, Storage, VPN servers with custom hardware. Install OS, control panels, deploy apps and websites. Manage SSH keys, billing, invoices, DNS, and service lifecycle.

SKILL.md

37.4 KB, as published. Nobody here has run it

[H1][ishosting-manager]

Dictum: Unified interface reduces API complexity.

<br>

Complete is*hosting infrastructure management through Python API wrapper.

Credentials

The script automatically searches for .env files in:

  1. Current directory
  2. Parent directory
  3. ~/.config/ishosting/

Required environment variables:

  • ISHOSTING_TOKEN - Your API token
  • ISHOSTING_BASE_URL - API base URL (must use https:// — the script rejects http:// to protect credentials)

Optional environment variables:

  • ISHOSTING_API_LANGUAGE - API language (auto-detected, see below)
  • ISHOSTING_BASE_AUTH - Basic auth credentials if needed

[CRITICAL] Pre-flight credential check

BEFORE running ANY ishosting command, you MUST verify credentials exist. Follow this order:

Step 1: Check for .env file in the project directory:

cat .env 2>/dev/null || echo "NO_ENV_FILE"

If .env exists and contains ISHOSTING_TOKEN and ISHOSTING_BASE_URL → credentials are OK, proceed. The Python script loads .env automatically. Do NOT check shell environment variables — they are NOT set; the script reads .env directly.

Step 2: If NO .env file found → ASK the user to provide:

  • ISHOSTING_TOKEN — API token
  • ISHOSTING_BASE_URL — API base URL
  • ISHOSTING_BASE_AUTH — Basic auth (optional)

Step 3: When user provides credentials → save them to .env in the project root:

cat > .env << 'EOF'
ISHOSTING_TOKEN=<token>
ISHOSTING_BASE_URL=<url>
ISHOSTING_BASE_AUTH=<auth>
EOF
chmod 600 .env

Step 4: Ensure .env is in .gitignore (prevents accidental credential commits):

grep -qxF '.env' .gitignore 2>/dev/null || echo '.env' >> .gitignore

This ensures credentials persist across sessions. Do NOT guess or invent credential values. Do NOT save ISHOSTING_API_LANGUAGE to .env — language is auto-detected from the user's messages via the --lang flag.

Language auto-detection

The --lang flag controls the API response language. Detect it automatically from the user's messages:

  • If the user writes in Russian (Cyrillic text), add --lang ru to every command
  • Otherwise, omit it (defaults to en)

Example:

# User wrote in Russian
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vps-list --lang ru

# User wrote in English (or any other language)
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vps-list

Do NOT ask the user about language. Just detect it from their messages.

Command defaults

[IMPORTANT] Zero-arg commands default to page=1, limit=30.

# Zero-arg commands
uv run .claude/skills/ishosting-manager/scripts/ishosting.py profile-view
uv run .claude/skills/ishosting-manager/scripts/ishosting.py services-list
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vps-list

Python execution

[CRITICAL] Always use uv run for executing Python scripts, never plain python3 or python.

# Correct - use uv run
uv run script.py

# Wrong - don't use plain python
python3 script.py  #
python script.py   #

[0][INTERACTION MODEL]

[CRITICAL] This skill operates in a step-by-step confirmation model. Every user-facing question is a hard pause — the agent MUST stop and wait for an answer before doing anything else.

STOP GATE — mandatory rule

Wherever you see [STOP GATE] in these instructions, you MUST:

  1. Output your question or summary to the user
  2. Immediately end your response — no further tool calls, no "proceeding...", no pre-emptive actions
  3. Wait for the user's next message before continuing

Why this matters: Running multiple steps without confirmation can create orders, charges, or server deployments the user did not explicitly approve. Each STOP GATE protects the user from unintended actions.

[FORBIDDEN] After a STOP GATE, you MUST NOT:

  • Call any tools (Bash, Read, etc.)
  • Assume a default answer and proceed
  • Say "I'll proceed with the default" or similar
  • Combine the question with the next action in the same message

[1][PROFILE]

uv run .claude/skills/ishosting-manager/scripts/ishosting.py profile-view

[2][SETTINGS]

uv run .claude/skills/ishosting-manager/scripts/ishosting.py profile-settings-view
uv run .claude/skills/ishosting-manager/scripts/ishosting.py profile-settings-edit --firstname "John" --lastname "Doe" --phone "+1234567890"
uv run .claude/skills/ishosting-manager/scripts/ishosting.py ssh-key-view
uv run .claude/skills/ishosting-manager/scripts/ishosting.py ssh-key-create --title "SshKeyName" --public "PublicKey"
uv run .claude/skills/ishosting-manager/scripts/ishosting.py ssh-key-delete --id 1196440

[3][SERVICES]

uv run .claude/skills/ishosting-manager/scripts/ishosting.py services-stats
uv run .claude/skills/ishosting-manager/scripts/ishosting.py services-list

[4][VPS]

Valid actions for vps-status-change: start, stop, reboot, force, cancel

uv run .claude/skills/ishosting-manager/scripts/ishosting.py vps-list
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vps-view --id 12345
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vps-edit --id 12345
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vps-status --id 12345
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vps-status-change --id 12345 --action start
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vps-status-change --id 12345 --action stop
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vps-status-change --id 12345 --action reboot
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vps-status-change --id 12345 --action force
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vps-status-change --id 12345 --action cancel
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vps-locations
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vps-plans --locations NL
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vps-plan-view --code vps-basic
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vps-configs --code vps-basic
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vps-ssh --id 12345
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vps-rdns-edit --id 12345 --protocol ipv4 --ip 1.2.3.4

[5][STORAGE]

Valid actions for storage-status-change: cancel

uv run .claude/skills/ishosting-manager/scripts/ishosting.py storage-list
uv run .claude/skills/ishosting-manager/scripts/ishosting.py storage-view --id 12345
uv run .claude/skills/ishosting-manager/scripts/ishosting.py storage-edit --id 12345
uv run .claude/skills/ishosting-manager/scripts/ishosting.py storage-status --id 12345
uv run .claude/skills/ishosting-manager/scripts/ishosting.py storage-status-change --id 12345 --action cancel
uv run .claude/skills/ishosting-manager/scripts/ishosting.py storage-locations
uv run .claude/skills/ishosting-manager/scripts/ishosting.py storage-plans --locations US
uv run .claude/skills/ishosting-manager/scripts/ishosting.py storage-plan-view --code storage-basic
uv run .claude/skills/ishosting-manager/scripts/ishosting.py storage-configs --code storage-basic
uv run .claude/skills/ishosting-manager/scripts/ishosting.py storage-ssh --id 12345

[6][DEDICATED]

Valid actions for dedicated-status-change: start, stop, reboot, cancel

uv run .claude/skills/ishosting-manager/scripts/ishosting.py dedicated-list
uv run .claude/skills/ishosting-manager/scripts/ishosting.py dedicated-view --id 12345
uv run .claude/skills/ishosting-manager/scripts/ishosting.py dedicated-edit --id 12345
uv run .claude/skills/ishosting-manager/scripts/ishosting.py dedicated-status --id 12345
uv run .claude/skills/ishosting-manager/scripts/ishosting.py dedicated-status-change --id 12345 --action start
uv run .claude/skills/ishosting-manager/scripts/ishosting.py dedicated-status-change --id 12345 --action stop
uv run .claude/skills/ishosting-manager/scripts/ishosting.py dedicated-status-change --id 12345 --action reboot
uv run .claude/skills/ishosting-manager/scripts/ishosting.py dedicated-status-change --id 12345 --action cancel
uv run .claude/skills/ishosting-manager/scripts/ishosting.py dedicated-locations
uv run .claude/skills/ishosting-manager/scripts/ishosting.py dedicated-plans --locations FI
uv run .claude/skills/ishosting-manager/scripts/ishosting.py dedicated-plans --locations FI --gpu true
uv run .claude/skills/ishosting-manager/scripts/ishosting.py dedicated-plan-view --code dedicated-basic
uv run .claude/skills/ishosting-manager/scripts/ishosting.py dedicated-configs --code dedicated-basic
uv run .claude/skills/ishosting-manager/scripts/ishosting.py dedicated-ssh --id 12345
uv run .claude/skills/ishosting-manager/scripts/ishosting.py dedicated-rdns-edit --id 12345 --protocol ipv4 --ip 1.2.3.4

[7][VPN]

Valid actions for vpn-status-change: start, stop, reboot, force, cancel

uv run .claude/skills/ishosting-manager/scripts/ishosting.py vpn-list
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vpn-view --id 12345
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vpn-edit --id 12345
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vpn-status --id 12345
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vpn-status-change --id 12345 --action start
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vpn-status-change --id 12345 --action stop
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vpn-status-change --id 12345 --action reboot
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vpn-status-change --id 12345 --action force
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vpn-status-change --id 12345 --action cancel
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vpn-locations
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vpn-plans
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vpn-plan-view --code vpn-basic
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vpn-configs --code vpn-basic
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vpn-rdns-edit --id 12345 --protocol ipv4 --ip 1.2.3.4

[7.5][PRE-VALIDATION]

Before calling billing-order-validate or billing-order-create, run the local pre-validator to catch incompatible hardware/software combinations without an API round-trip.

# Full order pre-validation
uv run .claude/skills/ishosting-manager/scripts/validators.py validate-order \
  --type dedicated --os "linux/ubuntu.24.x#64" --panel fastpanel --location FI

# OS/panel compatibility only
uv run .claude/skills/ishosting-manager/scripts/validators.py validate-os-panel \
  --type vps --os "linux/alma9#64" --panel cpanel

# Show full compatibility matrix
uv run .claude/skills/ishosting-manager/scripts/validators.py check-matrix --type vps

Output: {"valid": true/false, "errors": [...], "warnings": [...]}

Rules encoded: OS/Panel compat matrix (VPS + Dedicated), Windows restrictions (no panels/admin/monitoring), panel↔admin dependency, VPS disk>100GB↔backup, Dedicated RAID needs 2+ same drives, DDoS only in NL.

If valid: false → do NOT proceed with the API order. Show the errors to the user and suggest corrections. If warnings present → inform the user (e.g., "ticket-install" means support must install the panel manually).


[8][BILLING]

uv run .claude/skills/ishosting-manager/scripts/ishosting.py billing-configs
uv run .claude/skills/ishosting-manager/scripts/ishosting.py billing-promo --code PROMO2024
uv run .claude/skills/ishosting-manager/scripts/ishosting.py billing-order-validate --plan PLAN_CODE --location ber --payment balance --type vps
uv run .claude/skills/ishosting-manager/scripts/ishosting.py billing-order-create --plan PLAN_CODE --location ber --payment balance --type dedicated
uv run .claude/skills/ishosting-manager/scripts/ishosting.py billing-invoices
uv run .claude/skills/ishosting-manager/scripts/ishosting.py billing-invoice-view --id 12345
uv run .claude/skills/ishosting-manager/scripts/ishosting.py billing-invoice-status --id 12345
uv run .claude/skills/ishosting-manager/scripts/ishosting.py billing-invoice-pay --id 12345
uv run .claude/skills/ishosting-manager/scripts/ishosting.py billing-invoice-cancel --id 12345
uv run .claude/skills/ishosting-manager/scripts/ishosting.py billing-balance-add --amount 100
uv run .claude/skills/ishosting-manager/scripts/ishosting.py billing-balance-invoices
uv run .claude/skills/ishosting-manager/scripts/ishosting.py billing-balance-invoice-view --id 12345

Ordering with hardware/software options (VPS and Dedicated)

[IMPORTANT] VPS and Dedicated servers support additional hardware/software options beyond the base plan. Use the --additions parameter with JSON array.

Step 1: Get available options from configs:

uv run .claude/skills/ishosting-manager/scripts/ishosting.py vps-configs --code PLAN_CODE
uv run .claude/skills/ishosting-manager/scripts/ishosting.py dedicated-configs --code PLAN_CODE

Step 2: Extract option codes and category codes from configs:

Each option in the response includes both code and category.code:

{
  "name": "Nvidia 310",
  "code": "GPU_NVIDIA_310",
  "category": {"code": "PLATFORM_GPU"}
}

Step 3: Build additions array:

[
  {"code": "GPU_NVIDIA_310", "category": "PLATFORM_GPU"},
  {"code": "DDOS_BASIC_CODE", "category": "ADDITIONS_DDOS"},
  {"code": "DRIVE_SSD_100GB_CODE", "category": "ADDITIONS_PLATFORM_FIXED_DRIVE_SLOT_1"}
]

Step 4: Pass additions to order command:

# Dedicated server with GPU + DDoS
uv run .claude/skills/ishosting-manager/scripts/ishosting.py billing-order-create \
  --plan DEDICATED_PLAN \
  --location ber \
  --payment balance \
  --type dedicated \
  --additions '[{"code":"GPU_NVIDIA_310","category":"PLATFORM_GPU"},{"code":"DDOS_BASIC_CODE","category":"ADDITIONS_DDOS"}]'

# VPS with extra RAM + backup
uv run .claude/skills/ishosting-manager/scripts/ishosting.py billing-order-create \
  --plan VPS_PLAN \
  --location ams \
  --payment balance \
  --type vps \
  --additions '[{"code":"RAM_DDR4_2GB_CODE","category":"ADDITIONS_PLATFORM_FIXED_RAM"},{"code":"BACKUP_DAILY_CODE","category":"ADDITIONS_BACKUP"}]'

[CRITICAL] Always get category codes from the API response, never hardcode them!


[9][RECIPES]

Recipe A: Create and pay for a service order (VPS/VPN/Storage/Dedicated)

[CRITICAL] This is a multi-step process that REQUIRES user confirmation at key points.

Step 1: Determine service type

[IMPORTANT] Identify the service type from the user's request:

  • "VPS", "virtual server", "cloud server" → VPS
  • "VPN", "private network" → VPN
  • "dedicated server", "bare metal" → Dedicated
  • "storage", "file server" → Storage

Step 2: Determine location and plan

[CRITICAL] The flow differs by service type because of how plans and locations relate:

Flow A — VPS / Dedicated / Storage (location-first approach)

[IMPORTANT] Determine location FIRST to filter plans. This reduces API response from 2MB to ~200KB.

How locations work: For these service types, locations are embedded in the plans themselves (each plan has a location field). The *-locations commands fetch all plans and extract unique locations from them. Then you can filter plans by location using the --locations parameter.

Flow: Determine location → show filtered plans → user picks plan

  1. If user specified a location (e.g., "create VPS in Finland", "dedicated in NL"):

    • Extract location code from request
    • Skip to step 3 with that location
  2. If user did NOT specify a location:

    • Fetch locations:
    uv run .claude/skills/ishosting-manager/scripts/ishosting.py vps-locations
    uv run .claude/skills/ishosting-manager/scripts/ishosting.py dedicated-locations
    uv run .claude/skills/ishosting-manager/scripts/ishosting.py storage-locations
    
    • Present as aligned columns with location name and code
    • Ask user: "Which location? (enter the number or code)"
    • [STOP GATE] End your response here. Do NOT fetch plans. Do NOT assume a default location. Wait for user input.
  3. Fetch plans filtered by location:

# Use --locations parameter to filter
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vps-plans --locations FI
uv run .claude/skills/ishosting-manager/scripts/ishosting.py dedicated-plans --locations NL
uv run .claude/skills/ishosting-manager/scripts/ishosting.py storage-plans --locations US

For dedicated, can also filter by GPU/DDoS:

uv run .claude/skills/ishosting-manager/scripts/ishosting.py dedicated-plans --locations FI --gpu true
uv run .claude/skills/ishosting-manager/scripts/ishosting.py dedicated-plans --locations US --ddos DDOS_BASIC
  1. Present filtered plans (much smaller response).

  2. Ask user: "Which plan would you like? (enter the number or code)" [STOP GATE] End your response here. Do NOT fetch configs, OS options, or SSH keys. Wait for user to pick a plan.

Flow B — VPN (all plans share the same specs, location is chosen separately)

All VPN plans show a single default location (USA) but actually support 40+ locations via configs. So location must be determined first.

Flow: Show locations → user picks → show plans → user picks

  1. If user specified a location (e.g., "create VPN in NL"):

    • Use it, confirm: "I'll use Netherlands (NL). OK?"
    • Skip to showing plans
  2. If user did NOT specify a location:

    • Fetch locations:
    uv run .claude/skills/ishosting-manager/scripts/ishosting.py vpn-locations
    
    • Present as aligned columns:
    #   Location           Code   Extra cost
    1   USA, Chicago       US     -
    2   Netherlands        NL     -
    3   Germany            DE     -
    
    • Ask user: "Which location? (enter the number or code)"
    • [STOP GATE] End your response here. Do NOT fetch VPN plans. Do NOT assume a default location. Wait for user input.
  3. Then show VPN plans:

    uv run .claude/skills/ishosting-manager/scripts/ishosting.py vpn-plans
    
  4. Ask user: "Which plan would you like? (enter the number or code)" [STOP GATE] End your response here. Wait for user to pick a plan.

Important notes:

  • Extract plan code (e.g., 29_1m) from user choice
  • For VPS/Dedicated/Storage: location comes from the chosen plan
  • For VPN: location was determined in Step 2
  • Remember the service type — you'll need --type in validate and create steps!

Step 3: Get and show OS options and hardware additions (VPS and Dedicated only)

Skip this step for VPN and Storage — OS is preinstalled and cannot be changed; no hardware options available.

For VPS and Dedicated, fetch available configs:

uv run .claude/skills/ishosting-manager/scripts/ishosting.py vps-configs --code 29_1m
uv run .claude/skills/ishosting-manager/scripts/ishosting.py dedicated-configs --code dedicated-basic

Show available OS from configs. Ask user: "Which OS would you like to use?" [STOP GATE] End your response here. Do NOT ask about SSH keys or proceed to validation. Wait for user to choose an OS.

After the user picks OS — ask about hardware/software additions if applicable: "Would you like to add any hardware options (extra RAM, disk, DDoS protection, etc.)? If yes, I'll show you the available options. If no, we'll continue." [STOP GATE] End your response here. Wait for user answer about additions.

If user wants hardware/software options, extract the code and category.code from the configs response and build an additions array (see Section [8] for details).

Step 4: Setup SSH key (CRITICAL - do this BEFORE order creation)

[IMPORTANT] Always ask about SSH keys BEFORE creating the order so the key can be attached during provisioning.

Ask user: "Would you like to add an SSH key for secure access to your server? Options: A) use existing key from your machine, B) paste a new key, C) generate a new key pair, D) skip (you'll get root password by email)." [STOP GATE] End your response here. Do NOT check local SSH keys or query the API. Wait for user to choose an option.

Option A: Use existing SSH key from OS

Check if user has SSH keys locally:

cat ~/.ssh/id_ed25519.pub || cat ~/.ssh/id_rsa.pub

If found, show the public key and ask: "Use this SSH key?"

If user agrees:

  1. First, get their existing SSH keys from is*hosting profile:
uv run .claude/skills/ishosting-manager/scripts/ishosting.py ssh-key-view
  1. Check if this key already exists (compare public key). If not, add it:
uv run .claude/skills/ishosting-manager/scripts/ishosting.py ssh-key-create --title "My SSH Key" --public "ssh-ed25519 AAAA..."
  1. Note the key ID from the response or the existing keys list. You'll use this in the order.

Option B: User provides new key

Ask user to paste their public SSH key, then add it to their profile (same as Option A, step 2-3).

Option C: Generate new key pair

ssh-keygen -t ed25519 -C "ishosting-vps" -f ~/.ssh/ishosting_key -N ""
cat ~/.ssh/ishosting_key.pub

Show user the generated keys, then add public key to profile (same as Option A, step 2-3).

Option D: Skip SSH key

User can skip this step, but warn them: "You'll receive a root password via email, but SSH key authentication is more secure."

Step 5: Validate order and GET USER CONFIRMATION

[CRITICAL] Run validation and show the user a complete order summary.

[IMPORTANT] ALWAYS specify --type parameter matching the service type:

  • Use --type vps for VPS plans
  • Use --type vpn for VPN plans
  • Use --type storage for Storage plans
  • Use --type dedicated for Dedicated plans

Omitting --type will default to "vps" and cause "Wrong plan type" error if the plan is for a different service!

# VPS with SSH key
uv run .claude/skills/ishosting-manager/scripts/ishosting.py billing-order-validate --plan 29_1m --location NL --payment balance --type vps --os "linux/ubuntu24#64" --ssh-keys "1196440"

# With hardware options
uv run .claude/skills/ishosting-manager/scripts/ishosting.py billing-order-validate --plan 29_1m --location NL --payment balance --type vps --os "linux/ubuntu24#64" --ssh-keys "1196440" --additions '[{"code":"RAM_CODE","category":"RAM_CATEGORY"}]'

# Without SSH key
uv run .claude/skills/ishosting-manager/scripts/ishosting.py billing-order-validate --plan 29_1m --location NL --payment balance --type vps --os "linux/ubuntu24#64"

Present order summary as key-value lines (NOT a markdown table):

Service:     VPS
Plan:        Lite (29_1m)
Location:    Netherlands
OS:          Ubuntu 24.04 LTS
CPU:         1 core
RAM:         1 GB
Disk:        25 GB
SSH Key:     Attached (My SSH Key)
Auto-renew:  Enabled
Price:       $5.00/month

[IMPORTANT] Auto-renew is enabled by default. Show it in the order summary so the user can see it.

[CRITICAL] Auto-renew is controlled ONLY at payment time via --renew false on billing-invoice-pay. Do NOT try to disable it via *-edit --auto_renew false during order creation — the --renew flag on the payment command is the correct and only way to set it for new orders. If the user asks to disable auto-renew, remember this and apply --renew false when paying the invoice (Step 7).

Then explicitly ask: "Ready to create this order? (yes/no)"

[STOP GATE] End your response here. Do NOT call billing-order-create or any other command. Do NOT assume "yes". Wait for the user to explicitly type "yes" or "no".

Step 6: Create order (only after confirmation)

[IMPORTANT] ALWAYS include --type parameter matching the service type (vps/vpn/storage/dedicated).

Same arguments as validation, but use billing-order-create instead of billing-order-validate.

This returns {"order": {"invoice": {"id": 15718}, "services": [{"id": 12540}]}}.

Extract invoice ID and service ID. Inform user: "Order created! Invoice #15718, Service ID: 12540"

If SSH key was attached: "[OK] SSH key attached. You can connect with: ssh root@<server-ip>"

Step 7: Handle payment

[CRITICAL] After order creation, ALWAYS ask the user how they want to pay. Do NOT automatically pay from balance.

Step 7.1: Check current balance and invoice amount
uv run .claude/skills/ishosting-manager/scripts/ishosting.py billing-invoice-view --id 15718
uv run .claude/skills/ishosting-manager/scripts/ishosting.py profile-view
Step 7.2: Present payment options to user

Show the user:

  • Invoice amount: e.g., "$6.99"
  • Current balance: e.g., "$1,000,925.06"

Ask user to choose ONE of these payment options:

#  Option       Description
1  Balance      Pay the full amount from account balance
2  Method       Pay the full amount via payment gateway (crypto, card, etc.)
3  Partly       Use balance first, pay the remainder via payment gateway
4  Pay later    Skip payment for now, invoice remains pending

[STOP GATE] End your response here. Do NOT pay the invoice. Do NOT assume the user wants to pay from balance. Wait for the user to choose one of the 4 options above.


Option 1: Balance (balance only)
uv run .claude/skills/ishosting-manager/scripts/ishosting.py billing-invoice-pay --id 15718 --balance true

Check response:

  • If paid: true → "Payment successful! Invoice fully paid from balance."
  • If paid: false → "Insufficient balance. Choose a payment method for the remaining amount."

Option 2: Method (payment gateway only)
  1. Get available payment methods:
uv run .claude/skills/ishosting-manager/scripts/ishosting.py billing-configs
  1. Show payment methods as a table (same format as Recipe C — balance top-up). Ask user to choose.

  2. Pay with chosen method — --method flag only, no --balance:

uv run .claude/skills/ishosting-manager/scripts/ishosting.py billing-invoice-pay --id 15718 --method b_cryptomus

Check response:

  • If paid: true → "Payment successful!"
  • If payment_link exists → "Complete payment here: [link]"

Option 3: Partly (balance + payment gateway)

[IMPORTANT] This is a SINGLE API call with BOTH --balance and --method flags.

  1. Get available payment methods (same as Option 2, step 1-2).

  2. Pay with both balance and method in one call:

uv run .claude/skills/ishosting-manager/scripts/ishosting.py billing-invoice-pay --id 15718 --balance true --method b_cryptomus

The API will deduct available balance first, then generate a payment link for the remainder.

Check response:

  • If paid: true → "Payment successful! Fully covered by balance."
  • If paid: false + payment_link → Show: "Balance applied. Complete the remaining amount here: [link]"

Option 4: Pay later

No command needed. Simply inform user:

"Invoice #15718 ($6.99) is pending. You can pay it later."


Recipe B: Attach SSH key to existing service

When to use: To add or update SSH keys on an already-provisioned VPS/Storage/Dedicated server.

Step 1: Ask user for SSH key preference

"Would you like to attach an SSH key?"

  • Use existing SSH key from your OS
  • Enter a new SSH key
  • Create a new SSH key pair
  • Skip

Step 2: Get or create the key

Same flow as Recipe A, Step 4 (Options A/B/C).

Step 3: Add key to is*hosting profile

uv run .claude/skills/ishosting-manager/scripts/ishosting.py ssh-key-create --title "My SSH Key" --public "ssh-ed25519 AAAA..."

Step 4: Attach key to service

# For VPS
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vps-ssh --id 12540

# For Storage
uv run .claude/skills/ishosting-manager/scripts/ishosting.py storage-ssh --id 12540

# For Dedicated
uv run .claude/skills/ishosting-manager/scripts/ishosting.py dedicated-ssh --id 12540

Inform user: "[OK] SSH key attached to service."


Recipe C: Top up account balance

[CRITICAL] ALWAYS follow these steps when user asks to top up balance:

Step 1: Get and show available payment methods

ALWAYS run this command first:

uv run .claude/skills/ishosting-manager/scripts/ishosting.py billing-configs

Present payment methods as a formatted table:

#  Payment Method               Code           Min   Max       Fees       KYC
1  Crypto (Cryptomus)           b_cryptomus    $1    $10,000   None       No
2  Visa/Mastercard (Revolut)    b_revolut      $5    $10,000   +19% VAT   No
3  Visa/Mastercard (Overpay)    b_overpay      $5    $2,000    +4.5%      No

Show any VAT or fees, min/max limits, KYC requirements.

Step 2: Ask user to choose method and amount

"Please choose a payment method (enter the number or code) and specify the amount you'd like to add."

Validate amount is within the chosen method's min/max limits.

Step 3: Create top-up invoice

uv run .claude/skills/ishosting-manager/scripts/ishosting.py billing-balance-add --amount 50 --method b_cryptomus

Step 4: Provide payment link

Check response:

  • If paid: true → "[OK] Balance added successfully!"
  • If payment_link exists → "Complete payment here: [link]"

Recipe D: Manage service status

When to use: User wants to start, stop, restart, or perform other actions on a service.

Step 1: Get current status

# For VPS
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vps-status --id 12540

# For VPN
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vpn-status --id 12540

# For Storage
uv run .claude/skills/ishosting-manager/scripts/ishosting.py storage-status --id 12540

# For Dedicated
uv run .claude/skills/ishosting-manager/scripts/ishosting.py dedicated-status --id 12540

Show user current status.

Step 2: Execute action

uv run .claude/skills/ishosting-manager/scripts/ishosting.py {svc}-status-change --id 12540 --action start

[CRITICAL] Check the API response. Only confirm success if the response confirms the action was applied. If error → report actual error.


Recipe E: Cancel a service

When to use: User wants to cancel a VPS, VPN, Storage, or Dedicated service.

[CRITICAL] Cancellation is a destructive and irreversible operation. You MUST get explicit user confirmation before proceeding.

Step 1: Show current service info

Fetch the service details first so the user sees what they're cancelling:

uv run .claude/skills/ishosting-manager/scripts/ishosting.py vps-view --id 12345

Show the user: service name, plan, location, IP, expiration date.

Step 2: Request explicit confirmation

Ask the user clearly: "Are you sure you want to cancel service [name] (ID: [id])? This action is irreversible — the service will be terminated. (yes/no)"

[STOP GATE] End your response here. Do NOT run the cancel command. Do NOT assume yes. Wait for the user to explicitly type "yes" before proceeding.

Step 3: Execute cancellation (only after confirmation)

uv run .claude/skills/ishosting-manager/scripts/ishosting.py vps-status-change --id 12345 --action cancel
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vpn-status-change --id 12345 --action cancel
uv run .claude/skills/ishosting-manager/scripts/ishosting.py storage-status-change --id 12345 --action cancel
uv run .claude/skills/ishosting-manager/scripts/ishosting.py dedicated-status-change --id 12345 --action cancel

Check response. Report only: "Service (ID: 12345) has been cancelled." or "Failed to cancel service: [actual error message]". Nothing else.


Recipe F: Change auto-renew setting

When to use: User wants to enable or disable auto-renew on an already active service.

[CRITICAL] For NEW orders, auto-renew is set at payment time via --renew false on billing-invoice-pay (see Step 7 in Recipe A). Do NOT use *-edit to change auto-renew during order creation — it may fail on unpaid/pending services.

uv run .claude/skills/ishosting-manager/scripts/ishosting.py vps-edit --id 12345 --auto_renew false
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vpn-edit --id 12345 --auto_renew false
uv run .claude/skills/ishosting-manager/scripts/ishosting.py storage-edit --id 12345 --auto_renew false
uv run .claude/skills/ishosting-manager/scripts/ishosting.py dedicated-edit --id 12345 --auto_renew false

[CRITICAL] After executing the edit command, you MUST verify the change was applied:

  1. Check the API response — it must confirm updated: true
  2. Then fetch the service details to verify the new auto_renew value:
uv run .claude/skills/ishosting-manager/scripts/ishosting.py vps-view --id 12345
  1. Only report success if the auto_renew field in the response matches what was requested.
  2. If the response shows the old value, report: "The change was not applied. Current auto-renew status: [value]"

Recipe G: SSH safety when connecting to user's servers

[CRITICAL] Before executing ANY commands on a user's server via SSH, the agent MUST warn the user and obtain explicit confirmation. Never connect and run commands without the user's approval.

When to use: The agent is about to SSH into a user's VPS, Dedicated, or Storage server to perform operations.

Step 1: Display safety warning

Before connecting, always warn about risks: misconfiguration, service disruption, data loss, security exposure.

Step 2: Present the action plan

Show the user a numbered list of exactly what the agent intends to do on their server. Be specific about each step.

[IMPORTANT] The plan must list every command or operation the agent will perform. Do not hide steps or combine multiple actions into a single vague item.

Step 3: Request explicit user confirmation

Ask the user clearly: "Do you approve this plan? I will only proceed if you confirm. (yes/no)"

[STOP GATE] End your response here. Do NOT connect to the server or run any commands. Wait for the user's explicit approval.

If user says NO → ask what to change, revise plan. If any step fails → stop immediately and inform user.


[10][RESPONSE VERIFICATION]

[CRITICAL] You MUST check every API response before reporting results to the user. NEVER assume success. NEVER say "done" without verifying the response.

Rules:

  1. Always read the full API response — check status, error, and the actual data fields
  2. For action commands (*-edit, *-status-change, ssh-key-create, etc.) — verify the response contains confirmation (e.g., updated: true, changed: true, created: true)
  3. For edit commands — after a successful edit, fetch the resource again to confirm the change was actually applied (e.g., after vps-edit --auto_renew false, run vps-view and check that auto_renew is now false)
  4. If the API returns an error — report the actual error to the user, do not say the action succeeded
  5. If the response is empty or ambiguous — report that the result is unclear and suggest the user verify manually
  6. NEVER fabricate results — only report what the API actually returned

[11][OUTPUT]

Commands return: {"status": "success|error", ...}.

INDEX  PATTERN            RESPONSE
[1]    List commands       {items: object[]}
[2]    View commands       {id: int, item: object}
[3]    Action commands     {id: int, action: bool}
[4]    Create commands     {id: int, created: bool}
[5]    Payment commands    {id: int, paid: bool, payment_link?: string}

[12][FORMATTING]

[IMPORTANT] Never show raw JSON to the user.

[CRITICAL] Do NOT use markdown tables (pipes | and dashes ---). Many terminals and agents render them as ugly raw text. Use plain-text aligned columns instead.

Profile / Service details — use key: value lines:

Name:    Daniil
Email:   [email protected]
Balance: $56.50

Lists (VPS list, invoices, plans, SSH keys) — use space-aligned columns:

ID      Name                  Location    Plan    IP          Status
12345   My VPS                Netherlands Lite    1.2.3.4     Running
12346   Staging               Germany     Start   5.6.7.8     Stopped

Payment results — check the response:

  • If paid: true → "Payment successful! Invoice #15718 is paid."
  • If paid: false and payment_link exists - "Payment required. Complete payment here: [payment_link]"
  • If paid: false and no link - "Payment pending. You can pay later from your profile."

General rules:

  • Flatten nested JSON into readable fields (e.g. platform.config.cpu.name → CPU)
  • Omit empty, null, or irrelevant fields
  • Format prices with $ symbol
  • Format dates as human-readable (e.g. "Jan 16, 2026")
  • For long lists, show the most relevant columns only

[CRITICAL] Clean output — no internal leaks:

  • NEVER output TODO, TO_DO, FIXME, HACK, or any developer markers in user-facing text
  • NEVER expose raw JSON field names to the user (e.g., do NOT write "paid_at есть" or "auto_renew: true"). Translate them to human-readable labels (e.g., "Paid: Yes", "Auto-renew: enabled")
  • NEVER mix languages in a single phrase (e.g., "Оплачено: да (paid_at есть)"). Pick one language — match the user's language
  • NEVER show internal implementation details, placeholder text, or debugging notes
  • If a field value is unclear, either translate it to plain language or omit it entirely

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.