{"id":"1d81390d-b265-4a50-8ac4-5c28b73a79e0","shortId":"azVFhY","kind":"skill","title":"oops","tagline":"Deploy applications to Kubernetes via OOPS PaaS using the Python CLI script. Use when the user asks to deploy/release/ship an application to OOPS, create a new OOPS app, inspect a pipeline, configure an app's build/service/runtime/env-vars, or mentions oops, ZIP/Git deploys, hell","description":"# OOPS — Deploy applications to Kubernetes via CLI\n\nOOPS is a Kubernetes-based PaaS. This skill teaches the agent how to use the\nrepo-vendored Python script `skills/oops/scripts/oops.py` to drive the end-to-end\nloop: create app → configure build → bind env → set service → set runtime →\ntrigger pipeline → wait for rollout.\n\n## Confirmation policy\n\n**This is a production deployment system. Confirm with the user before executing every write step.**\n\nBefore running any write command (create, set, deploy, stop), use the `AskUserQuestion` tool to show the user exactly what you are about to do and wait for explicit approval. Do not batch multiple steps into a single confirmation — confirm each step individually. Only proceed after the user approves.\n\nExample confirmation question: \"Run the following command?\" with the full command as the option label.\n\nRead-only commands (`ls`, `get`, `status`) do not require confirmation.\n\n## When to use\n\nThe user says things like \"deploy X to oops\", \"create a new app on oops\",\n\"show me the pipeline for web-test on oops\", \"ship this zip to oops\" — use\nthis skill.\n\n## When NOT to use\n\n- The user is developing/debugging OOPS itself → this skill is for\n  *operating* OOPS, not contributing to it. Point them at the OOPS repo's\n  CLAUDE.md (https://github.com/wellCh4n/oops/blob/main/CLAUDE.md) instead.\n- The user wants to operate the cluster directly with `kubectl` → do not go\n  through OOPS.\n\n## Prerequisites\n\n### 1. Locate the script\n\nThe CLI is a single Python script (`skills/oops/scripts/oops.py`) with no third-party dependencies. Invoke from the repo root:\n\n```bash\npython skills/oops/scripts/oops.py <subcommand>\n```\n\nNo compilation, no `pip install`, no build step needed.\n\n### 2. Authentication\n\nThe script **only accepts a pre-issued access token** — no username/password\nlogin. Tokens look like `sk-oops-xxxxxxxxxxxxxxxx` and are issued by the\nuser in the OOPS UI (\"Reset Access Token\").\n\nThree ways to pass it (highest precedence first):\n\n```bash\n# A. Environment variables (recommended for one session)\nexport OOPS_ENDPOINT=http://localhost:8080\nexport OOPS_TOKEN=sk-oops-...\n\n# B. Per-invocation flags\npython skills/oops/scripts/oops.py --endpoint http://localhost:8080 --token sk-oops-... ns ls\n\n# C. Persist to ~/.oops/config.toml\npython skills/oops/scripts/oops.py auth set --endpoint http://localhost:8080 --token sk-oops-...\npython skills/oops/scripts/oops.py auth status   # verify\n```\n\n**If the user has not provided a token, stop and ask** — do not guess an\nendpoint or invent a token.\n\n## End-to-end deploy workflow\n\nBelow is the smallest verified loop. Every step matters; skipping any one\nbreaks the deploy in subtle ways.\n\n### Step 1 — Discover namespace, environment, domain\n\n```bash\npython skills/oops/scripts/oops.py ns ls       # list namespaces\npython skills/oops/scripts/oops.py env ls      # list environments (redacted — no K8s token leaked)\npython skills/oops/scripts/oops.py domain ls   # list managed domains for service exposure\n```\n\nNote down the target namespace (e.g. `default`) and environment (e.g.\n`dev`) — every later command needs them.\n\n### Step 2 — Create the application\n\n```bash\npython skills/oops/scripts/oops.py app create -n <namespace> <app-name> --description \"<one-line summary>\"\n```\n\n- `<app-name>` must follow Kubernetes naming (lowercase alphanum + dashes).\n- If the app already exists the command errors out. **Use `python skills/oops/scripts/oops.py app get -n <ns> <app-name>` first to check.**\n\n### Step 3 — Configure build (most common pitfall)\n\n#### ZIP source (most common)\n\n```bash\npython skills/oops/scripts/oops.py app build set -n <ns> <app> \\\n    --source zip \\\n    --dockerfile-type user \\\n    --dockerfile-content \"$(cat path/to/Dockerfile)\"\n```\n\n**Hard constraint**: `--dockerfile-type user` **requires**\n`--dockerfile-content` (inline text). `--dockerfile-path` alone is not\nenough. The Dockerfile content is injected into the build env on every\ndeploy, so the ZIP itself does **not** need to contain a Dockerfile.\n\n#### Git source\n\n```bash\npython skills/oops/scripts/oops.py app build set -n <ns> <app> \\\n    --source git \\\n    --repository \"https://github.com/owner/repo.git\" \\\n    --build-image \"maven:3.9-eclipse-temurin-21-alpine\" \\\n    --dockerfile-type builtin \\\n    --dockerfile-path \"Dockerfile\"\n```\n\n`builtin` reads the real Dockerfile from the repository.\n\n### Step 4 — Bind to environments\n\n```bash\npython skills/oops/scripts/oops.py app env set -n <ns> <app> --env <env-name>\n# multi-env: --env dev --env prod\n```\n\nWithout an env binding, deploy fails.\n\n### Step 5 — Configure service exposure\n\n```bash\npython skills/oops/scripts/oops.py app service set -n <ns> <app> \\\n    --port <container-port> \\\n    --env-host <env>=<host>[:https]\n# example: --env-host dev=hello.example.com:https\n```\n\nThe host should be a subdomain under a managed domain from `python skills/oops/scripts/oops.py domain ls`.\nFor example if `example.com` is managed, set the host to `hello.example.com`.\n\n### Step 6 — Configure runtime (**easy to forget; replicas default to 0**)\n\n```bash\npython skills/oops/scripts/oops.py app runtime set -n <ns> <app> \\\n    --env \"<env>=cpu:1/2,mem:64/128,replicas:1\"\n```\n\nStrict format: `cpu:<request>/<limit>,mem:<request>/<limit>,replicas:<n>`.\nCPU is in cores, no unit suffix (e.g. `0.1`, `0.5`, `1`, `2`). Memory is a plain number in Mi, no suffix (e.g. `64`, `128`) — OOPS appends `Mi` automatically.\n**Skip this and replicas stays at 0 — the Pod never starts.** This is the\nmost common cause of \"deploy succeeded but I can't reach the app\".\n\n### Step 7 — Trigger the deploy\n\n#### ZIP mode\n\n```bash\n# Package the source first (enter the dir, then zip its contents)\ncd path/to/source && zip -r /tmp/<app>.zip .\n\n# One shot: upload + trigger + wait for rollout\npython skills/oops/scripts/oops.py deploy zip -n <ns> <app> --env <env> --file /tmp/<app>.zip --wait\n```\n\n`--wait` polls pipeline status until `SUCCEEDED` / `FAILED` / `ERROR`.\n**Without `--wait` the command returns immediately after triggering** and\ndoes not surface the build result.\n\n#### Git mode\n\n```bash\npython skills/oops/scripts/oops.py deploy git -n <ns> <app> --env <env> --branch main --wait\n```\n\nUses the repository configured in step 3; `--branch` is optional.\n\n### Step 8 — Verify\n\n```bash\npython skills/oops/scripts/oops.py pipeline ls -n <ns> <app>   # recent runs\npython skills/oops/scripts/oops.py app get -n <ns> <app>       # app summary\n```\n\n## Read-only inspection commands\n\n```bash\npython skills/oops/scripts/oops.py app build get -n <ns> <app>                # build config\npython skills/oops/scripts/oops.py app service get -n <ns> <app>              # service config\npython skills/oops/scripts/oops.py app runtime get -n <ns> <app>              # runtime spec\npython skills/oops/scripts/oops.py app env ls -n <ns> <app>                   # env bindings\npython skills/oops/scripts/oops.py app config get -n <ns> <app> --env <env>   # ConfigMap entries\npython skills/oops/scripts/oops.py pipeline get -n <ns> <app> <pipeline-id>   # single pipeline detail\n```\n\n## Output format\n\nAll commands default to human-readable tables. For programmatic parsing\npass `--json`:\n\n```bash\npython skills/oops/scripts/oops.py --json app ls -n default | jq '.[].name'\n```\n\n`--json` is a **global flag** and must appear before the subcommand.\n\n## Troubleshooting\n\n| Symptom | Cause | Fix |\n|---|---|---|\n| `401 Unauthorized` | Token wrong or unset | Run `auth status`; re-run `auth set` |\n| `405 Method Not Allowed` | Tried to delete a resource | `/openapi` intentionally blocks DELETE. Ask the user to delete in the UI. |\n| `Dockerfile content is required when type is USER` | Missing `--dockerfile-content` | See the hard constraint in step 3. |\n| `Application is being deployed` | Previous deploy still in flight | Wait; check `pipeline ls`; or `pipeline stop`. |\n| Pipeline `SUCCEEDED` but Pod count is 0 | Runtime spec never set (replicas=0) | Run step 6, then **re-deploy**. |\n| External request times out but `kubectl exec … wget localhost` works | Ingress / DNS issue, outside OOPS | Check DNS / Traefik — not in scope here. |\n| Second deploy reports `ERROR` but the Pod is healthy | Known OOPS edge case in rollout-state judgment | Check `kubectl get pod`; if `Running` you're fine. |\n\n## Hard boundaries\n\n- **Do not try to delete applications via CLI** — `/openapi` deliberately\n  blocks DELETE. Let the user delete in the UI.\n- **Do not pick namespace / env / host on behalf of the user** — list them\n  with `ns ls` / `env ls` / `domain ls`, and ask if the user didn't say.\n- **Pre-deploy checklist**: build ✓ env ✓ service ✓ runtime ✓ — miss any\n  one and the deploy either fails or the app is unreachable.\n- **When zipping the source, `cd` into the source dir first, then `zip -r\n  /tmp/foo.zip .`** — don't include the outer directory or the build\n  container won't find the Dockerfile.","tags":["oops","wellch4n","agent-skills","agents","devops","graphical-ops","kubernetes","pipline-operators"],"capabilities":["skill","source-wellch4n","skill-oops","topic-agent-skills","topic-agents","topic-devops","topic-graphical-ops","topic-kubernetes","topic-pipline-operators"],"categories":["oops"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/wellCh4n/oops/oops","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add wellCh4n/oops","source_repo":"https://github.com/wellCh4n/oops","install_from":"skills.sh"}},"qualityScore":"0.455","qualityRationale":"deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 10 github stars · SKILL.md body (8,914 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-13T07:07:01.148Z","embedding":null,"createdAt":"2026-05-11T19:08:28.219Z","updatedAt":"2026-05-13T07:07:01.148Z","lastSeenAt":"2026-05-13T07:07:01.148Z","tsv":"'/.oops/config.toml':387 '/openapi':1031,1157 '/owner/repo.git':620 '/tmp':831,847 '/tmp/foo.zip':1230 '/wellch4n/oops/blob/main/claude.md)':253 '0':733,787,1084,1090 '0.1':761 '0.5':762 '1':271,449,747,763 '1/2':743 '128':776 '2':306,499,764 '21':629 '3':536,891,1061 '3.9':625 '4':648 '401':1008 '405':1022 '5':674 '6':724,1093 '64':775 '64/128':745 '7':809 '8':896 '8080':361,377,394 'accept':311 'access':316,339 'agent':62 'allow':1025 'alon':579 'alphanum':515 'alpin':630 'alreadi':520 'app':29,35,82,202,506,519,529,549,611,655,681,737,807,908,911,921,929,937,945,953,987,1214 'appear':1000 'append':778 'applic':3,22,46,502,1062,1154 'approv':141,160 'ask':18,414,1035,1189 'askuserquest':124 'auth':390,401,1015,1020 'authent':307 'automat':780 'b':368 'base':56 'bash':294,349,454,503,546,608,652,678,734,815,875,898,918,983 'batch':144 'behalf':1175 'bind':85,649,670,950 'block':1033,1159 'boundari':1148 'branch':882,892 'break':442 'build':84,303,538,550,590,612,622,871,922,925,1200,1239 'build-imag':621 'build/service/runtime/env-vars':37 'builtin':634,639 'c':384 'case':1132 'cat':562 'caus':797,1006 'cd':827,1221 'check':534,1072,1113,1138 'checklist':1199 'claude.md':250 'cli':12,50,276,1156 'cluster':261 'command':117,167,171,179,495,523,861,917,971 'common':540,545,796 'compil':298 'config':926,934,954 'configmap':958 'configur':33,83,537,675,725,888 'confirm':96,104,150,151,162,186 'constraint':565,1058 'contain':603,1240 'content':561,573,585,826,1044,1054 'contribut':240 'core':756 'count':1082 'cpu':742,750,753 'creat':25,81,118,199,500,507 'dash':516 'default':488,731,972,990 'delet':1028,1034,1039,1153,1160,1164 'deliber':1158 'depend':288 'deploy':2,42,45,102,120,195,428,444,594,671,799,812,842,878,1065,1067,1097,1121,1198,1209 'deploy/release/ship':20 'descript':509 'detail':967 'dev':492,664,694 'developing/debugging':230 'didn':1193 'dir':822,1225 'direct':262 'directori':1236 'discov':450 'dns':1109,1114 'dockerfil':556,560,567,572,577,584,605,632,636,638,643,1043,1053,1245 'dockerfile-cont':559,571,1052 'dockerfile-path':576,635 'dockerfile-typ':555,566,631 'domain':453,474,478,706,710,1186 'drive':74 'e.g':487,491,760,774 'easi':727 'eclips':627 'eclipse-temurin':626 'edg':1131 'either':1210 'end':77,79,425,427 'end-to-end':76,424 'endpoint':359,375,392,419 'enough':582 'enter':820 'entri':959 'env':86,463,591,656,659,662,663,665,669,687,692,741,845,881,946,949,957,1172,1184,1201 'env-host':686,691 'environ':351,452,466,490,651 'error':524,857,1123 'everi':110,436,493,593 'exact':130 'exampl':161,690,713 'example.com':715 'exec':1104 'execut':109 'exist':521 'explicit':140 'export':357,362 'exposur':481,677 'extern':1098 'fail':672,856,1211 'file':846 'find':1243 'fine':1146 'first':348,532,819,1226 'fix':1007 'flag':372,997 'flight':1070 'follow':166,511 'forget':729 'format':749,969 'full':170 'get':181,530,909,923,931,939,955,963,1140 'git':606,616,873,879 'github.com':252,619 'github.com/owner/repo.git':618 'github.com/wellch4n/oops/blob/main/claude.md)':251 'global':996 'go':267 'guess':417 'hard':564,1057,1147 'healthi':1128 'hell':43 'hello.example.com':695,722 'highest':346 'host':688,693,698,720,1173 'https':689,696 'human':975 'human-read':974 'imag':623 'immedi':863 'includ':1233 'individu':154 'ingress':1108 'inject':587 'inlin':574 'inspect':30,916 'instal':301 'instead':254 'intent':1032 'invent':421 'invoc':371 'invok':289 'issu':315,330,1110 'jq':991 'json':982,986,993 'judgment':1137 'k8s':469 'known':1129 'kubectl':264,1103,1139 'kubernet':5,48,55,512 'kubernetes-bas':54 'label':175 'later':494 'leak':471 'let':1161 'like':194,323 'list':459,465,476,1179 'localhost':360,376,393,1106 'locat':272 'login':320 'look':322 'loop':80,435 'lowercas':514 'ls':180,383,458,464,475,711,902,947,988,1074,1183,1185,1187 'main':883 'manag':477,705,717 'matter':438 'maven':624 'mem':744,751 'memori':765 'mention':39 'method':1023 'mi':771,779 'miss':1051,1204 'mode':814,874 'multi':661 'multi-env':660 'multipl':145 'must':510,999 'n':508,531,552,614,658,684,740,844,880,903,910,924,932,940,948,956,964,989 'name':513,992 'namespac':451,460,486,1171 'need':305,496,601 'never':790,1087 'new':27,201 'note':482 'ns':382,457,1182 'number':769 'one':355,441,833,1206 'oop':1,7,24,28,40,44,51,198,204,214,219,231,238,247,269,326,336,358,363,367,381,398,777,1112,1130 'oper':237,259 'option':174,894 'outer':1235 'output':968 'outsid':1111 'paa':8,57 'packag':816 'pars':980 'parti':287 'pass':344,981 'path':578,637 'path/to/dockerfile':563 'path/to/source':828 'per':370 'per-invoc':369 'persist':385 'pick':1170 'pip':300 'pipelin':32,92,208,852,901,962,966,1073,1076,1078 'pitfal':541 'plain':768 'pod':789,1081,1126,1141 'point':243 'polici':97 'poll':851 'port':685 'pre':314,1197 'pre-deploy':1196 'pre-issu':313 'preced':347 'prerequisit':270 'previous':1066 'proceed':156 'prod':666 'product':101 'programmat':979 'provid':409 'python':11,70,280,295,373,388,399,455,461,472,504,527,547,609,653,679,708,735,840,876,899,906,919,927,935,943,951,960,984 'question':163 'r':830,1229 're':1018,1096,1145 're-deploy':1095 're-run':1017 'reach':805 'read':177,640,914 'read-on':176,913 'readabl':976 'real':642 'recent':904 'recommend':353 'redact':467 'replica':730,746,752,784,1089 'repo':68,248,292 'repo-vendor':67 'report':1122 'repositori':617,646,887 'request':1099 'requir':185,570,1046 'reset':338 'resourc':1030 'result':872 'return':862 'rollout':95,839,1135 'rollout-st':1134 'root':293 'run':114,164,905,1014,1019,1091,1143 'runtim':90,726,738,938,941,1085,1203 'say':192,1195 'scope':1118 'script':13,71,274,281,309 'second':1120 'see':1055 'servic':88,480,676,682,930,933,1202 'session':356 'set':87,89,119,391,551,613,657,683,718,739,1021,1088 'ship':215 'shot':834 'show':127,205 'singl':149,279,965 'sk':325,366,380,397 'sk-oop':365,379,396 'sk-oops-xxxxxxxxxxxxxxxx':324 'skill':59,222,234 'skill-oops' 'skills/oops/scripts/oops.py':72,282,296,374,389,400,456,462,473,505,528,548,610,654,680,709,736,841,877,900,907,920,928,936,944,952,961,985 'skip':439,781 'smallest':433 'sourc':543,553,607,615,818,1220,1224 'source-wellch4n' 'spec':942,1086 'start':791 'state':1136 'status':182,402,853,1016 'stay':785 'step':112,146,153,304,437,448,498,535,647,673,723,808,890,895,1060,1092 'still':1068 'stop':121,412,1077 'strict':748 'subcommand':1003 'subdomain':702 'subtl':446 'succeed':800,855,1079 'suffix':759,773 'summari':912 'surfac':869 'symptom':1005 'system':103 'tabl':977 'target':485 'teach':60 'temurin':628 'test':212 'text':575 'thing':193 'third':286 'third-parti':285 'three':341 'time':1100 'token':317,321,340,364,378,395,411,423,470,1010 'tool':125 'topic-agent-skills' 'topic-agents' 'topic-devops' 'topic-graphical-ops' 'topic-kubernetes' 'topic-pipline-operators' 'traefik':1115 'tri':1026,1151 'trigger':91,810,836,865 'troubleshoot':1004 'type':557,568,633,1048 'ui':337,1042,1167 'unauthor':1009 'unit':758 'unreach':1216 'unset':1013 'upload':835 'use':9,14,65,122,189,220,226,526,885 'user':17,107,129,159,191,228,256,333,406,558,569,1037,1050,1163,1178,1192 'username/password':319 'variabl':352 'vendor':69 'verifi':403,434,897 'via':6,49,1155 'wait':93,138,837,849,850,859,884,1071 'want':257 'way':342,447 'web':211 'web-test':210 'wget':1105 'without':667,858 'won':1241 'work':1107 'workflow':429 'write':111,116 'wrong':1011 'x':196 'xxxxxxxxxxxxxxxx':327 'zip':217,542,554,597,813,824,829,832,843,848,1218,1228 'zip/git':41","prices":[{"id":"2de9ccd7-3ec7-401a-a89e-4429bb414164","listingId":"1d81390d-b265-4a50-8ac4-5c28b73a79e0","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"wellCh4n","category":"oops","install_from":"skills.sh"},"createdAt":"2026-05-11T19:08:28.219Z"}],"sources":[{"listingId":"1d81390d-b265-4a50-8ac4-5c28b73a79e0","source":"github","sourceId":"wellCh4n/oops/oops","sourceUrl":"https://github.com/wellCh4n/oops/tree/main/skills/oops","isPrimary":false,"firstSeenAt":"2026-05-11T19:08:28.219Z","lastSeenAt":"2026-05-13T07:07:01.148Z"}],"details":{"listingId":"1d81390d-b265-4a50-8ac4-5c28b73a79e0","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"wellCh4n","slug":"oops","github":{"repo":"wellCh4n/oops","stars":10,"topics":["agent-skills","agents","devops","graphical-ops","kubernetes","pipline-operators"],"license":"apache-2.0","html_url":"https://github.com/wellCh4n/oops","pushed_at":"2026-05-12T09:38:21Z","description":"OOPS: Kubernetes Is All You Need. One-stop ops platform based on Kubernetes","skill_md_sha":"2f589a10609577714032f555fff5cad8fc760e9e","skill_md_path":"skills/oops/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/wellCh4n/oops/tree/main/skills/oops"},"layout":"multi","source":"github","category":"oops","frontmatter":{"name":"oops","description":"Deploy applications to Kubernetes via OOPS PaaS using the Python CLI script. Use when the user asks to deploy/release/ship an application to OOPS, create a new OOPS app, inspect a pipeline, configure an app's build/service/runtime/env-vars, or mentions oops, ZIP/Git deploys, helloworld deploys, namespace/environment/pipeline/configmap."},"skills_sh_url":"https://skills.sh/wellCh4n/oops/oops"},"updatedAt":"2026-05-13T07:07:01.148Z"}}