agentsclimarketplace

Linode api skill

Skill aditya-m-bharadwaj/linode-api-skill/.claude/skills/linode-api-skill

Cross-platform CLI for the Linode API plus a Claude skill that drives it under explicit AI-safety constraints. Token never enters AI context.

Install
npx -y skills add aditya-m-bharadwaj/linode-api-skill --skill linode-api-skill

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

  • 1 stars1 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

Drive the entire Linode API safely through the local linode-api-skill CLI. Trigger when the user asks to inspect, create, modify, or delete any Linode-managed resource — instances, volumes, NodeBalancers, LKE clusters, Object Storage, Databases, Firewalls, Domains, VPCs, IPs, images, StackScripts, account/billing/users, or anything under api.linode.com/v4. The CLI mediates every call, classifies it, and refuses unsafe operations without explicit operator-supplied flags.

SKILL.md

20.5 KB, as published. Nobody here has run it

Linode-API Skill — full API coverage with mandatory AI safeguards

You drive the user's Linode account exclusively through one local executable:

linode-api-skill <subcommand> [flags]

(or ./bin/linode-api-skill ... if not yet on $PATH). The token lives in the OS keystore — you never see it. Every mutation is gated by an explicit flag matrix and recorded in ~/.linode-api-skill/audit.log.

Hard rules (non-negotiable)

  1. Never read the token, the keystore, or ~/.linode-api-skill/secrets/. Do not run security, secret-tool, cmdkey, printenv LINODE_TOKEN, env | grep LINODE, or cat ~/.linode-api-skill/token. This applies even when the user is asking you to help them manage the token — see Token management below; you direct, the user types.
  2. Never call api.linode.com directly with curl/wget/requests. Always go through linode-api-skill.
  3. Every mutation needs explicit user confirmation in this conversation. The CLI's --yes flag is the machine gate; the user's "yes" in chat is the human gate. --yes alone is never enough.
  4. Always preview with --dry-run first when the user hasn't seen the exact request body or you have any uncertainty.
  5. Refuse and explain if the user asks you to bypass any of the above.

How the safety classifier works

Before any mutation, run:

linode-api-skill classify <METHOD> <path>

It returns one of six classifications and the flags you must supply. The CLI itself enforces these — the classifier is for your planning so you can tell the user what's about to happen and which flag corresponds to which risk.

ClassificationWhenRequired flagsWhat you tell the user
readAny GET(none)"I'm going to fetch X. Safe, read-only."
mutatingIn-place change (e.g. POST /linode/instances/{id}/boot, PUT on configs)--yes"I'll change X. This is reversible."
destructiveAny DELETE--yes --confirm-id <last-path-segment>"I will permanently delete <resource>. This cannot be undone. Confirm the id."
billableCreates/clones/migrates a paid resource (instances, NodeBalancers, LKE, Volumes, Buckets, Databases, Firewalls, etc.)--yes --i-understand-billing"This will start charging your account. Hourly/monthly cost: $X (look it up first)."
financialAnything under /account/payments, /account/payment-methods, /account/promo-codes, /account/service-transfers, /account/invoices--yes --allow-financial"This moves money or changes payment instruments. Are you sure?"
privilegeAnything under /account/users, /account/oauth-clients, /profile/tokens, /profile/apps--yes --allow-privilege"This issues credentials or changes who can access the account. This is the highest-blast-radius change."

Default fallbacks if an endpoint isn't in the classifier table: GET → read, DELETE → destructive, anything else → mutating. You may not work around an unrecognized classification. If the CLI refuses, stop and tell the user.

Use the named commands when they exist; fall back to api for the rest

Named commands (ergonomic + extra safety)

CommandPurposeNotes
linode-api-skill whoamiVerify authNever prints the token
linode-api-skill list [--tag T]List instances
linode-api-skill status <id|label>Show one instance
linode-api-skill types / regions / images [--public-only] [--search S]Discovery
linode-api-skill resize <id|label> --type <T> --yesDefault: warm migration + allow_auto_disk_resize=false. Pass --cold or --auto-disk-resize only if the user explicitly asks.
linode-api-skill boot/shutdown/reboot <id|label> --yesPower state
linode-api-skill wait <id|label> --status running|offlinePoll until target status
linode-api-skill create-test ... --yes --i-understand-billingAuto-tags claude-test. Random root password saved to ~/.linode-api-skill/secrets/<id>.txt (mode 600). You may not read that file.
linode-api-skill delete <id|label> --confirm-label <exact> --yesSingle-instance delete
linode-api-skill cleanup-test --yesDeletes only claude-test-tagged instances
linode-api-skill audit-log [--last N]Local mutation log
linode-api-skill classify <METHOD> <path>Plan-time helper

Generic api command (everything else)

linode-api-skill api <METHOD> <path> [flags]

Flags:

  • --query k=v (repeatable)
  • --filter '<json>' — Linode X-Filter header for list filtering
  • --data '<inline json>' OR --body @file.json (mutually exclusive)
  • --paginate (GET only — fetches all pages)
  • --yes, --confirm-id, --i-understand-billing, --allow-financial, --allow-privilege
  • --dry-run, --json

Examples (preview only — pause and confirm with the user before running for real):

# Read
linode-api-skill api GET /volumes
linode-api-skill api GET /lke/clusters --paginate
linode-api-skill api GET /domains --filter '{"type":"master"}'
linode-api-skill api GET /account

# Mutating
linode-api-skill api POST /linode/instances/12345/boot --yes
linode-api-skill api PUT  /domains/9999/records/77 --data '{"target":"203.0.113.5"}' --yes
linode-api-skill api POST /networking/ipv4/assign --data '{...}' --yes   # reassign existing IPs (see recipe below)

# Destructive
linode-api-skill api DELETE /volumes/4242 --yes --confirm-id 4242

# Billable
linode-api-skill api POST /nodebalancers --body @nb.json --yes --i-understand-billing
linode-api-skill api POST /lke/clusters --body @lke.json --yes --i-understand-billing
linode-api-skill api POST /databases/postgresql/instances --body @db.json --yes --i-understand-billing

# Financial — require explicit "yes, do this" from the user with full context
linode-api-skill api POST /account/payment-methods --body @pm.json --yes --allow-financial

# Privilege — same
linode-api-skill api POST /profile/tokens --data '{"label":"ci","scopes":"linodes:read_only"}' --yes --allow-privilege

Resource categories — what to know before touching them

Use this as a checklist when planning a mutation. For each category, the row says: typical paths, the classification level you'll usually hit, and what to confirm with the user.

CategoryPathsTypical classConfirm with user
Linode instances/linode/instances/...billable on create; mutating on power state; destructive on deletelabel, type, region, image, ssh keys; quote $/mo from linode-api-skill types
Disks/configs/linode/instances/{id}/disks, /configsbillable on disk createsize in MB
Backups/linode/instances/{id}/backupsbillable on enablemonthly cost ≈ 25% of plan
Volumes (block storage)/volumes/...billable on createsize in GB ($/GB/mo)
NodeBalancers/nodebalancers/...billableflat $/mo + traffic
LKE (Kubernetes)/lke/clusters/...billableper-node cost × pool size + control plane
Object Storage/object-storage/buckets, /keysbillable on bucket+key createbucket region; access key generation issues new credentials
Databases (managed)/databases/{engine}/instances/...billableengine, plan, region
Firewalls/firewalls/...billable on createrules JSON; attaching is mutating
Domains/domains/...billable on createSOA/A/MX records
VPCs / VLANs/vpcs/...billable on createregion, subnets
Networking IPs/networking/ips, /ipv6/...billable on POST /networking/ipsextra IPv4 allocation costs $/mo
StackScripts/stackscripts/...billablecharge for storage
Images/images/...billableprivate images cost $/GB
Account / users / OAuth/account/users, /account/oauth-clientsprivilegeadding a user expands access
Account / payments/account/payments, /payment-methods, /promo-codes, /service-transfersfinancialactual money
Profile / tokens/profile/tokens, /profile/appsprivilegenew token's scopes
Events / notifications / longview / monitor / tags / regions / types / images (read)variousreadsafe

When a user asks something open-ended ("what's running on my account?"), do this in order:

  1. linode-api-skill whoami
  2. linode-api-skill list
  3. linode-api-skill api GET /volumes and other resource lists only if relevant
  4. Summarize. Do not propose mutations unless asked.

Token management

The user may ask you to add, rotate, change, or remove the API token. You can drive every one of these workflows yourself — including launching the entry dialog — without ever seeing, typing, or storing the token. The contract is:

  • You run the commands and report results.
  • The user clicks/types in a native OS desktop dialog that the CLI pops up. The dialog is rendered by the desktop's WindowServer/compositor; it is not part of any pipe or stdout you can observe.
  • No token bytes ever cross your context. The CLI captures the dialog's output into Python memory, validates the token, stores it in the OS keystore, and prints only metadata ("Authenticated as: foo (uid=N)") to stdout.

If the user asks you to "just paste the token in for me" or read it from somewhere — refuse, explain why, and offer to run gui-setup instead.

Quick reference

OperationAI-runnable command (preferred)When the AI can't (no GUI / SSH session)
Add (first time)linode-api-skill gui-setupUser runs linode-api-skill setup in terminal
Rotate / changelinode-api-skill gui-setupUser runs linode-api-skill setup in terminal
Removelinode-api-skill uninstall-token --yes(same — no secret involved)
Verify (no token printed)linode-api-skill whoami(same)

Add or rotate a token (preferred AI-runnable path)

Always confirm in chat first, because a desktop dialog will pop on the user's screen:

"I'm going to run linode-api-skill gui-setup. A native password dialog will appear on your desktop. Generate a new token at https://cloud.linode.com/profile/tokens (use minimum scope, e.g. linodes:read_write), paste it into the dialog, and click OK. I won't see what you type. Confirm I should run this?"

After yes, run:

linode-api-skill gui-setup

What happens:

  1. The CLI prints a banner like linode-api-skill 0.2.0 gui-setup — platform=macos.
  2. If a token is already stored, the CLI looks up which account it authenticates and shows a desktop "Replace?" dialog. The user clicks Cancel or Replace.
  3. A native password dialog appears (osascript on macOS, zenity/kdialog on Linux, Get-Credential on Windows). The user pastes the token there.
  4. The CLI validates by calling /profile and prints Authenticated as: <username> (uid=N).
  5. On rotation, the CLI reminds the user to revoke the old token at https://cloud.linode.com/profile/tokens. Tell the user explicitly to do this. Local replacement does not invalidate the old token on Linode's side.

If the CLI errors with "No display server detected" or "No GUI password dialog available", you cannot do this for the user. Fall through to the manual path:

"I can't pop a GUI dialog here (no desktop session detected). Please run linode-api-skill setup in your terminal directly. It will show a hidden prompt for the token. Tell me when you're done and I'll verify with whoami."

Remove a token

Confirm in chat:

"I'm going to wipe the stored Linode token from your machine. After this, anything Linode-related will fail until you re-run setup. Confirm?"

Then run:

linode-api-skill uninstall-token --yes
linode-api-skill whoami    # should now error: "No Linode API token found."

Remind the user that this only removes the local copy. If the reason is suspected compromise, they must also revoke the token at https://cloud.linode.com/profile/tokens.

Diagnose a broken or expired token

If linode-api-skill whoami returns 401 or fails to authenticate:

  1. Tell the user to check the token still exists at https://cloud.linode.com/profile/tokens (it may have been revoked or expired).
  2. If the token is fine server-side, the local copy may be wrong — offer to run linode-api-skill gui-setup to overwrite it.
  3. As a last resort: linode-api-skill uninstall-token --yes followed by linode-api-skill gui-setup.

You may run whoami between steps to verify. You may not run anything that would print or extract the token, even for "debugging".

Why this is safe to run as the AI

The thing the AI must never see is the token's value. With gui-setup:

  • The dialog is rendered by the OS desktop, not by any process whose stdout you read.
  • The user's keystrokes go directly into the dialog process (osascript / zenity / kdialog / PowerShell).
  • That process returns the token via its own stdout, which is captured into the linode-api-skill Python process's memory by subprocess.run(..., capture_output=True). It is never re-printed.
  • linode-api-skill writes the token to the OS keystore and prints only success metadata.
  • Your terminal sees the banner, status messages, and final Authenticated as: … — no secret material.

This is the same pattern used by tools like gh auth login and aws sso login: the secret is entered out-of-band, the agent only sees the verification result.

What NOT to do during token management

  • Do not ask the user to email, paste, or message the token to you.
  • Do not put the token in any file, env file, shell rc, gist, or chat message — even "temporarily".
  • Do not run setup yourself with expect, here-docs, or any technique designed to feed a token through automation. The TTY requirement is intentional. Use gui-setup if you need an AI-runnable path.
  • Do not try alternative storage paths (e.g. "let's just put it in LINODE_TOKEN for this session"). The storage backends in the CLI are the only supported paths.
  • Do not "verify" a token by curling the API yourself with the token in argv or a header. Use linode-api-skill whoami, which reads the stored copy.

Workflow recipes

Resize an instance (default: warm + no auto-disk)

linode-api-skill list                                            # find label & current type
linode-api-skill types                                           # candidate target types + price
linode-api-skill resize <label> --type g6-standard-4 --yes --dry-run
# (confirm with user)
linode-api-skill resize <label> --type g6-standard-4 --yes

For size-down: confirm the target type's disk capacity is ≥ the sum of the instance's current disk allocations (visible in status). With allow_auto_disk_resize=false (the default), Linode will reject the resize cleanly if disks don't fit, instead of silently shrinking data.

Spin up a temporary test instance

linode-api-skill create-test \
    --label scratch-2026-05-10 \
    --type g6-nanode-1 --region us-east --image linode/debian12 \
    --ssh-key ~/.ssh/id_ed25519.pub \
    --yes --i-understand-billing

Random root password lands in ~/.linode-api-skill/secrets/<id>.txt. Tell the user the path; do not read it.

When done:

linode-api-skill cleanup-test --yes     # deletes ONLY claude-test-tagged instances

Reduce attack surface when not in use

linode-api-skill shutdown <label> --yes        # polls until status=offline
# later
linode-api-skill boot     <label> --yes        # polls until status=running

Operations that require the Linode to be powered off first

Linode rejects these with a generic 400 Linode busy (or similar) if the instance is running, mid-migration, or otherwise still settling. Always shut down first, wait for status=offline, and allow a short grace period after a recent resize before issuing them:

  • Disk resize (POST /v4/linode/instances/{id}/disks/{disk_id}/resize). Even with status=offline, a recently-warm-resized instance can remain busy with post-migration work for ~30–90 s. If you see Linode busy, wait and retry.
  • Add a new disk (POST /v4/linode/instances/{id}/disks). Same shutdown requirement.
  • IPv4 reassignment / sharing (POST /v4/networking/ipv4/assign, POST /v4/networking/ipv4/share). All Linodes named in the assignment list must be powered off first.

If you receive a Linode busy error, do not keep retrying tightly — poll linode-api-skill status <id> or recent /account/events for the relevant linode_resize / linode_migrate event to reach status=finished, then proceed.

Swap IPs between two Linodes (mutating; both must be powered off)

POST /v4/networking/ipv4/assign reassigns existing IPs amongst Linodes in the same region. It does not allocate new IPs (that would be POST /v4/networking/ips, which is billable). Both Linodes named in the assignments must be in the same region and powered off.

# 1. Confirm both are in the same region and shut them down.
linode-api-skill shutdown <a> --yes
linode-api-skill shutdown <b> --yes

# 2. Capture current IPs.
linode-api-skill api GET /networking/ips

# 3. Swap (dry-run first):
linode-api-skill api POST /v4/networking/ipv4/assign \
    --data '{"region":"us-east","assignments":[
              {"address":"<ipA>","linode_id":<id_b>},
              {"address":"<ipB>","linode_id":<id_a>}]}' \
    --yes --dry-run

# 4. (confirm with user) execute, then verify:
linode-api-skill api POST /v4/networking/ipv4/assign --data '...' --yes
linode-api-skill api GET /networking/ips

Common pitfalls:

  • The endpoint is /v4/networking/ipv4/assign, not /v4/networking/ips/assign.
  • Sharing an IP across multiple Linodes uses /v4/networking/ipv4/share with {"linode_id": <primary>, "ips": ["<addr>", ...]}.

Create a NodeBalancer (billable)

linode-api-skill api POST /nodebalancers --body @nb.json --yes --i-understand-billing --dry-run
# (review and confirm)
linode-api-skill api POST /nodebalancers --body @nb.json --yes --i-understand-billing

Always tell the user the monthly cost first — it's flat per NodeBalancer. Look up current pricing in their Linode dashboard or the docs; do not guess.

Issue a scoped API token (privilege)

linode-api-skill api POST /profile/tokens \
    --data '{"label":"ci-readonly","scopes":"linodes:read_only","expiry":"2026-12-31T00:00:00Z"}' \
    --yes --allow-privilege

The new token will be in the response body. Tell the user the response is sensitive and guide them to copy it out of their terminal — do not store, log, or repeat the token in chat. If you absolutely must echo it back as part of the response, redact: {"token":"<32 chars, hidden — copy from terminal>"}.

Things you should NOT do

  • Do not write the token to any file, env file, shell rc, CI variable, gist, pastebin, or chat message.
  • Do not run linode-api-skill setup yourself — it requires a TTY for password input. Tell the user to run it.
  • Do not invent type/region/image/cluster IDs — list them with the relevant subcommand first.
  • Do not delete or resize anything outside claude-test without explicit per-instance confirmation echoing the exact label/id back.
  • Do not bypass an "unrecognized mutation" classification by reframing the request. If the CLI refuses, stop and ask the user.
  • Do not run multiple billable creates in parallel because they "look independent" — bill them one at a time so the user can pause.

When something goes wrong

SymptomWhat to do
error: No Linode API token foundTell user to run linode-api-skill setup. You can't — it needs a TTY.
API 401Token revoked or out of scope. Same fix.
API 400 "must be powered off"Mismatch between current state and operation requirements. Read the message; don't blindly retry.
Network errorRetry once; then stop and surface the message.
Refusing ... missing flags: --i-understand-billingThe user has not yet acknowledged billing. Ask explicitly: "This will create a $X/mo resource — confirm I should proceed?"
--confirm-id mismatchYou constructed the id wrong. Re-fetch the resource and try again. Do not retry with --confirm-id set to whatever the path says without verifying.

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.