Update to Network Solutions
Snapshot Nov 9, 2026 · 18:08 UTC · version 2.2.0
Collection source: downloaded plugin package.
Instructions updated for app-detect-and-plan
Skill instructions — Now says: 1.7.4 run `npm i -g @network-solutions/cli` so `netsol` is on PATH and use `npx netsol`, and stop. Never substitute a private endpoint, demo tool, When the...
Observed in instructions or declared skills. Runtime behavior has not been tested.
Up to 3 plugins free · no card required.
All fields and original values.
Skill instructions
Nov 5, 2026 · 18:09 UTC
1.7.1 install `netsol-cli`, and stop. Never substitute a private endpoint, demo tool, **`codex mcp login`** before plan — use **`netsol capabilities plan`** after | Full read-only plan | Inspect + catalog match, then `netsol capabilities...
Nov 9, 2026 · 18:08 UTC
1.7.4 run `npm i -g @network-solutions/cli` so `netsol` is on PATH and use `npx netsol`, and stop. Never substitute a private endpoint, demo tool, When the CLI path is intended, do not run a separate Node/npm version preflight before the...
Compare saved observations
Download comparison JSONSKILL.md text changes
− removed · + added
--- before +++ after @@ -3,7 +3,7 @@ description: Codex only. Inspect the current repository, detect its runtime, and produce a validated Network Solutions deployment plan with an exact hosting plan and quote. Read-only — stops before authentication and purchase. -version: 1.7.1 +version: 1.7.4 --- # App Detect and Plan (Network Solutions) @@ -78,18 +78,45 @@ 3. **Trusted Network Solutions hosted continuation** when offered to the user. If none of the three is available, tell the user how to add the MCP server or -install `netsol-cli`, and stop. Never substitute a private endpoint, demo tool, +run `npm i -g @network-solutions/cli` so `netsol` is on PATH and use `npx netsol`, and stop. Never substitute a private endpoint, demo tool, or guessed plan. +When the CLI path is intended, do not run a separate Node/npm version preflight before the bootstrap below. If `npm` or `npx` is unavailable, or `npx netsol version` / global CLI install fails because of Node or npm version limits, give Node.js LTS (>= 22.12) install guidance, stop, and wait for user confirmation. + +**CLI bootstrap (strict order):** Run each step as a **separate** shell command — do not chain the version probe with repository scans, `command -v`, bare `netsol version`, or install. + +1. Probe first: + +```bash +npx netsol version +``` + +2. **Only if** step 1 fails because the CLI is not installed, install globally, then retry: + +```bash +npm i -g @network-solutions/cli +npx netsol version +``` + +(Alternatively: `pnpm add -g @network-solutions/cli` or `bun add -g @network-solutions/cli` when the user uses those package managers.) + +Do **not** run `npm i -g @network-solutions/cli` (or any install) until step 1 has been attempted. Do **not** use `command -v netsol` or bare `netsol version` **instead of** the first `npx netsol version` probe. + +Require `data.cli_version` >= `0.2.0` from the version event. + +**CLI install anti-patterns:** Do not run `npm install --prefix` to `/tmp`, `/private/tmp`, or any side directory. Do not invoke `node_modules/.bin/netsol` by absolute path. Do not install before the `npx netsol version` probe. + +Workflow steps in this skill use **`npx netsol …`**. + Planning does not require MCP OAuth. When the CLI path is intended, do not run -**`codex mcp login`** before plan — use **`netsol capabilities plan`** after +**`codex mcp login`** before plan — use **`npx netsol capabilities plan`** after catalog match (public plan steps need no login). ### Use-case routing (when multiple paths are available) | Use case | Prefer | Why | | --- | --- | --- | -| Full read-only plan | Inspect + catalog match, then `netsol capabilities plan [path] --runtime <catalog-id> [--recipe-id <id>]` | Detect first; pass a catalog id; CLI re-validates against the catalog | +| Full read-only plan | Inspect + catalog match, then `npx netsol capabilities plan [path] --runtime <catalog-id> [--recipe-id <id>]` | Detect first; pass a catalog id; CLI re-validates against the catalog | | MCP available but CLI missing | MCP tools (Path B below) | Detect first; fetch catalog; declare a catalog ID | | Both MCP and CLI available | **CLI for planning** after catalog match; MCP only if CLI is missing or fails with "command not found" | CLI re-validates your declaration | @@ -234,7 +261,7 @@ Prefer obtaining the catalog so you see `data.runtimes` before declaring: ```bash -netsol mcp call deployment_list_supported_runtimes +npx netsol mcp call deployment_list_supported_runtimes ``` (Or call MCP `deployment_list_supported_runtimes` when the CLI path is not used @@ -244,13 +271,13 @@ freeform**. On **unknown** or **multiple**, stop or ask — do **not** run `capabilities plan` yet. -### A1. Plan — `netsol capabilities plan [path] --runtime <catalog-id> [--recipe-id <id>]` +### A1. Plan — `npx netsol capabilities plan [path] --runtime <catalog-id> [--recipe-id <id>]` Pass only the **catalog** runtime id from A0. `--recipe-id` is optional; when omitted the CLI derives it from the catalog entry. ```bash -netsol capabilities plan [path] --runtime nodejs --recipe-id nodejs-npm-start +npx netsol capabilities plan [path] --runtime nodejs --recipe-id nodejs-npm-start ``` Parse the NDJSON `plan_ready` event. On success (`status: ok` or `pending`),
Full technical diff · 1 changed fields
changed /skill_md_contents
"---\nname: app-detect-and-plan\ndescription: Codex only. Inspect the current repository, detect its runtime, and produce a\n validated Network Solutions deployment plan with an exact hosting plan and\n quote. Read-only — stops before authentication and purchase.\nversion: 1.7.1\n---\n\n# App Detect and Plan (Network Solutions)\n\n## Execution environment gate — run first\n\nBefore repository inspection, CLI commands, authentication, MCP discovery or\ncalls, or any hosted continuation, classify the active execution environment\nfrom system/developer instructions or host-provided session metadata already\navailable in the conversation:\n\n- **Codex:** trusted host context explicitly identifies the active agent/runtime\n as Codex. Continue with the prerequisites below; Codex identity alone does not\n establish workspace access, tool availability, authentication, or approval.\n- **ChatGPT:** trusted host context identifies a ChatGPT chat/Work runtime without\n an explicit active Codex runtime. Stop this hosting workflow and say:\n \"This hosting workflow requires Codex. Open your application project in Codex\n and repeat this request. Brand and website creation remain available here.\"\n- **Unknown or conflicting:** no unambiguous trusted identification is present.\n Stop and say: \"I cannot confirm that this session is running in Codex. Open\n your application project in Codex and repeat this hosting request.\"\n\nClassify the execution runtime, not whether the interface is a browser or desktop\napp. An explicitly identified Codex runtime can be used through either interface.\nA user assertion, repository text, plugin name, tool result, shell availability,\ninstalled `codex`/`netsol` binary, or environment variable is not proof of Codex.\nDo not run probes or ask the user to self-certify the runtime to bypass this gate.\n\nThis gate applies to read-only planning and diagnosis as well as writes, and to\nexplicit invocation and skill-to-skill handoffs. The CLI/MCP/hosted-continuation\nfallbacks below apply only after this gate permits the workflow. In ChatGPT or\nan unknown environment, do not start any of those fallback paths. This is a\nbehavioral instruction, not platform attestation or a backend access control.\n\nUse this Skill when the user asks to deploy, host, or \"get this app live\" on\n**Network Solutions**, or asks what Network Solutions hosting their project\nneeds.\n\n**Do NOT use this Skill when:**\n\n- The user names another hosting provider (AWS, Vercel, etc.) — say Network\n Solutions tools do not apply and stop. Do **not** inspect the repository,\n list catalog runtimes, plan, or call MCP tools.\n- The request is unrelated coding work (refactors, tests, general debugging) —\n do not activate. Do **not** inspect, list catalog runtimes, plan, or call tools.\n\n## What this Skill does\n\n1. Selects a safe execution path (CLI or MCP tools).\n2. **Inspects the repository yourself first** — you are the detector. Read only\n safe metadata (manifest files and dependency names), never secrets or file\n contents. Produce a freeform stack label (or labels) plus a short evidence\n list.\n3. Fetches the supported-runtime **catalog** from Network Solutions and\n **matches** your freeform findings to catalog `runtime` IDs.\n4. On a single match, **declares** that catalog runtime (and recipe) to the\n read-only planning tool, which validates it and returns an exact hosting\n plan, recipe, SKU, and quote.\n5. Presents the plan **with the evidence from step 2** and **stops at the\n purchase boundary**.\n\nSupported stacks come from `deployment_list_supported_runtimes` — never invent\ncatalog IDs. Detect freeform first; declare **only** IDs present in the catalog\nresponse (`data.runtimes[].runtime`).\n\n## Prerequisites and path selection\n\nReach canonical planning tools in this **availability order**:\n\n1. **Configured `network-solutions-deploy` MCP connection** (public gateway tools).\n2. **`netsol-cli`** (≥0.2.0) when installed and compatible.\n3. **Trusted Network Solutions hosted continuation** when offered to the user.\n\nIf none of the three is available, tell the user how to add the MCP server or\ninstall `netsol-cli`, and stop. Never substitute a private endpoint, demo tool,\nor guessed plan.\n\nPlanning does not require MCP OAuth. When the CLI path is intended, do not run\n**`codex mcp login`** before plan — use **`netsol capabilities plan`** after\ncatalog match (public plan steps need no login).\n\n### Use-case routing (when multiple paths are available)\n\n| Use case | Prefer | Why |\n| --- | --- | --- |\n| Full read-only plan | Inspect + catalog match, then `netsol capabilities plan [path] --runtime <catalog-id> [--recipe-id <id>]` | Detect first; pass a catalog id; CLI re-validates against the catalog |\n| MCP available but CLI missing | MCP tools (Path B below) | Detect first; fetch catalog; declare a catalog ID |\n| Both MCP and CLI available | **CLI for planning** after catalog match; MCP only if CLI is missing or fails with \"command not found\" | CLI re-validates your declaration |\n\nNever call tools excluded from the compatibility baseline (see\n`netsol-cli/contracts/compatibility/README.md`) or any write, purchase, auth,\ndeploy, DNS, log, or rollback tool from this Skill.\n\n---\n\n## Detecting the runtime (detect first, then catalog)\n\nOrder matters:\n\n1. **Inspect the repository** at its root **before** fetching the catalog.\n2. Run a **preflight inspect** (manifest-first; evidence = files present, not\n framework brands):\n 1. **Choose project root** — repo root, or the user-selected package\n directory in a monorepo.\n 2. **Monorepo markers** (when at repo root): `turbo.json`,\n `pnpm-workspace.yaml`, `lerna.json`, or `workspaces` in root `package.json`\n → **ask which package root** to deploy before planning. Until the user\n chooses a package root, do **not** assign a stack label from nested paths\n such as `apps/web/package.json`.\n 3. **Strong signals at the chosen root:**\n - **Node.js** — `package.json` exists (evidence: lockfile if present —\n `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`; optional\n `scripts.start` or `main`). Use the short freeform label **`Node.js`**\n (not “Node.js application”) — do not infer or name a framework brand.\n - **FastAPI** — `fastapi` appears in `requirements.txt` or\n `pyproject.toml`. Use the short freeform label **`FastAPI`**.\n - **Other stacks** (Ruby, Django, Java, …) — name them from safe metadata\n only with short labels such as **`Ruby`**, **`Java/Maven`** (e.g. Ruby\n from `main.rb` / `Gemfile`; Java/Maven from `pom.xml`).\n 4. Produce **freeform** stack label(s) and a short **evidence list**. Copy\n evidence strings **verbatim** from the repository inventory (e.g.\n `package.json: root manifest`, not paraphrases like “root package.json\n manifest”).\n3. **Then** obtain the catalog and **match** freeform findings to catalog\n `runtime` IDs (see **Catalog id vs freeform** below).\n\nRules:\n\n- Read manifest files and dependency **names** only. Never open `.env`, keys,\n or credentials; never read source bytes, versions, or secret values. When\n `.env` is listed in the repository inventory, add a `refuse_secret_access`\n step, set secret refusal flags, and **omit every `.env` line from the evidence\n list** — evidence stays limited to safe manifest entries only (e.g.\n `package.json: root manifest`).\n- A `Dockerfile`, `Procfile`, `docker-compose.yml`, or CI config is **not** a\n supported runtime signal. A repository that contains only those is a\n container-only repo — that is an **unknown** outcome, not a match.\n- After a **valid catalog plan**, the Deploy skill may create a root `Dockerfile`\n for image build and record local user consent under\n `.networksolutions/dockerfile.json`. That is a post-plan packaging step — it\n does **not** change detection rules and must **not** be suggested here as a\n way to force an unsupported stack to match.\n- After the catalog match, decide exactly one outcome:\n - **one match** — declare that catalog runtime (e.g. `nodejs`, `fastapi`) via\n Path A or Path B. Only the **plan/recommend** step carries the declared\n catalog runtime; inspection, catalog listing, and user-choice prompts do\n **not** declare a runtime yet.\n - **unknown** — zero catalog matches. Stop with `UNSUPPORTED_STACK`. No plan\n call; no best-effort deploy. See **Reporting an unsupported stack** below.\n - **multiple** — more than one catalog match (e.g. Node.js app with\n `package.json` and FastAPI backend) → ask which supported stack to deploy;\n do not guess and do not recommend a plan until the user chooses.\n\n### Reporting an unsupported stack\n\n**Reuse** the freeform stack + evidence from step 1 (no second detection pass)\nand give the developer exactly three things, then stop:\n\n1. **What you found** — the stack name with its evidence (e.g. \"Java/Maven via\n `pom.xml`\"). When step 1 identified nothing, say so plainly and name the\n files you did see (e.g. \"only a `Dockerfile`, no recognized runtime\n manifest\").\n2. **Why you cannot proceed** — that runtime is not in the Network Solutions\n supported-runtime catalog.\n3. **The supported runtimes** — from the catalog (`data.runtimes[].runtime`) or\n the error's `data.supported`. Include those catalog runtime ids (e.g.\n `nodejs`, `fastapi`) and the literal status `UNSUPPORTED_STACK` in the user\n message. Reuse prior evidence strings **verbatim** in the message.\n\n**Never suggest adding, creating, renaming, or scaffolding a detection file.**\nDo not tell the developer to add `package.json`, `requirements.txt`,\n`pyproject.toml`, or any other manifest so the app becomes detectable or\nsupported. Refuse scaffolding with the phrase **“Manifest scaffolding is\nrefused.”** without echoing filenames next to words like add, create, or\nscaffold (even when refusing a user request to add those files).\n\n### Catalog id vs freeform\n\nFreeform inspection evidence is **not** a valid `--runtime` / declare value.\n\n| Freeform evidence (inspect) | Catalog `runtime` id (declare / `--runtime`) |\n| --- | --- |\n| Short label `Node.js`; root `package.json` at chosen project root | `nodejs` |\n| Short label `FastAPI`; dependency / requirement name `fastapi` | `fastapi` |\n| Short label `Ruby` | (no catalog match → `UNSUPPORTED_STACK`) |\n| Short label `Java/Maven` | (no catalog match → `UNSUPPORTED_STACK`) |\n\nHard rules:\n\n- `--runtime` and MCP `runtime` must equal some `data.runtimes[].runtime` from\n the catalog.\n- **Never** pass a dependency name, display label, or framework brand as the\n catalog runtime (e.g. do not use a package name from `dependencies` as\n `--runtime`). Dependency name `fastapi` happens to match catalog id `fastapi`;\n any Node.js app maps to catalog id **`nodejs`**.\n- Do not invent ids. If the catalog has no match, that is **unknown** — stop.\n\n### Example — unsupported Ruby app\n\nAfter inspecting `main.rb` you already know the stack is Ruby. After the\ncatalog has no match, stop with a message like:\n\n> This looks like a **Ruby** application (`main.rb`). Network Solutions managed\n> deployment currently supports **nodejs** and **fastapi** only, so I can't\n> proceed. Supported runtimes: `nodejs`, `fastapi`.\n\n### Example — container-only or Java repository\n\nA repo with only a `Dockerfile` (or a Java/Maven service with `pom.xml`) has no\ncatalog match. Name what you saw, give the reason, list the catalog, and stop:\n\n> This repository has only a `Dockerfile` and no recognized runtime manifest, so\n> I can't identify a supported stack. Network Solutions managed deployment\n> currently supports **nodejs** and **fastapi** only. Status:\n> `UNSUPPORTED_STACK`.\n\nDo **not** append anything like \"add `package.json` or `requirements.txt` and I\ncan continue\".\n\n---\n\n## Path A — Preferred: `netsol-cli` (when installed, ≥0.2.0)\n\nComplete **inspect → catalog match → single catalog id** before planning.\n\n### A0. Catalog match (required before plan)\n\nPrefer obtaining the catalog so you see `data.runtimes` before declaring:\n\n```bash\nnetsol mcp call deployment_list_supported_runtimes\n```\n\n(Or call MCP `deployment_list_supported_runtimes` when the CLI path is not used\nfor that step.)\n\nThen map freeform findings to a catalog `runtime` id using **Catalog id vs\nfreeform**. On **unknown** or **multiple**, stop or ask — do **not** run\n`capabilities plan` yet.\n\n### A1. Plan — `netsol capabilities plan [path] --runtime <catalog-id> [--recipe-id <id>]`\n\nPass only the **catalog** runtime id from A0. `--recipe-id` is optional; when\nomitted the CLI derives it from the catalog entry.\n\n```bash\nnetsol capabilities plan [path] --runtime nodejs --recipe-id nodejs-npm-start\n```\n\nParse the NDJSON `plan_ready` event. On success (`status: ok` or `pending`),\npresent fields from `data` (see **Presentation checklist**). On\n`UNSUPPORTED_STACK` or `VALIDATION_ERROR`, stop — no best-effort deploy.\n\nThe CLI fetches the catalog again and re-validates your declaration, then calls\ncanonical gateway tools on your behalf. That internal fetch is fine and does\n**not** replace A0: you must still match and pass a real catalog id (never a\ndep or display name). You do not need to duplicate `deployment_recommend_plan`\nmanually when this command succeeds.\n\n---\n\n## Path B — Fallback: MCP tools (CLI unavailable)\n\nUse only these planning tools via the configured `network-solutions-deploy` MCP server:\n\n- `deployment_list_supported_runtimes`\n- `deployment_recommend_plan`\n- `deployment_validate_plan` (optional)\n- `deployment_get_recipe_requirements` (optional)\n\n### B1. Detect the runtime yourself (first)\n\nInspect the repository as described in **Detecting the runtime** above. Keep the\nfreeform label(s) and evidence list. Never authenticate, and never read `.env`,\nkeys, or credentials. Refuse secret access **only** when `.env` appears in the\nrepository inventory; otherwise do not add a secret-refusal step and do not set\nsecret refusal flags.\n\n### B2. Fetch the catalog (second)\n\nCall `deployment_list_supported_runtimes` and read `data.runtimes`: each entry\nhas `runtime`, `recipe`, `min_plan`, and build/start commands. Match your\nfreeform findings to these **catalog ids** (not dep names). On **unknown** or\n**multiple**, follow the outcomes above — do not call `deployment_recommend_plan`\nuntil there is exactly one chosen catalog runtime. Always list the catalog\nafter inspection, including when asking for a package root or runtime choice.\n\n### B3. Recommend plan (declare a catalog ID)\n\n```json\n{\"runtime\": \"nodejs\", \"recipe_id\": \"nodejs-npm-start\"}\n```\n\nCall `deployment_recommend_plan` with the matched catalog runtime (and\noptionally `recipe_id`). Record this planning step as **`recommend_plan`** —\nnever as `capabilities_plan` (CLI-only). You may include an optional `evidence_summary`\n(manifest files and dependency names) — it is audit-only and never changes the\nrecommendation. Never send `project_signals`; never send `repo_path` in\nproduction paths; never declare a freeform name or dep name that is not a\ncatalog `runtime` id.\n\n### B4. Optional enrichment\n\n- `deployment_validate_plan` with `deployment_plan_id` → `required_env_vars` (names only).\n- `deployment_get_recipe_requirements` with `recipe_id` → required files and env-var **names** (never values).\n\n---\n\n## Result interpretation\n\n| Result | Action |\n| --- | --- |\n| `status: requires_action` (or CLI `plan_ready` pending) | Valid plan exists — present checklist fields; save handles |\n| Agent-side `unknown` (no catalog match) | Reuse step-1 stack + evidence; give reason; list catalog; stop; never call recommend/plan; never suggest adding detection files |\n| `error_code: UNSUPPORTED_STACK` | Reuse step-1 detection if available; list `data.supported` if present; stop; never best-effort deploy; never suggest adding detection files |\n| `error_code: VALIDATION_ERROR` | Your declaration was rejected (unknown recipe or runtime/recipe mismatch) — report the literal `VALIDATION_ERROR`, list catalog runtime ids to recheck, and keep the catalog runtime id you attempted in your declared runtime; do not retry blindly |\n| Other errors | Report `summary` and `error_code`; retry once if `retryable` |\n\n## Presentation checklist\n\n### When invoked by Deploy to Network Solutions\n\nReturn plan, runtime, recipe, SKU, quote, evidence, commands, environment names,\nand workflow handles to the calling deployment workflow **internally**. Do not\npresent this section's standalone plan summary. The deploy workflow's stricter\nfour-field output contract overrides the presentation rules below. The\nuser-facing message for deploy-internal handoff must be **generic only** — never\ninclude runtime, recipe, SKU, quote reference, deployment plan id, workflow id,\nor any other plan fact value. Example:\n\n> A validated plan was returned internally to the calling deployment workflow;\n> user-facing deployment output remains controlled by that workflow.\n\n### On a successful plan\n\nBefore stopping, show the user:\n\n- **Runtime** and **recipe** (and `recipe_id` when returned)\n- **The evidence from local inspection** (manifest files, key dependency names)\n- **Build/start commands** when returned\n- **Plan name and SKU** (`data.product_requirement` or CLI `plan_ready` equivalent)\n- **Quote reference and expiry** (`quote_reference`, `quote_expires_at`)\n- **Required environment variable names** only (from validate/recipe tools)\n- **`workflow_id`** and **`deployment_plan_id`** from `state_handles` or CLI `plan_ready` data\n\nFinish with: \"To proceed, purchase/confirm the hosting plan — the Deploy to\nNetwork Solutions Skill continues from workflow `<workflow_id>`.\"\n\n### On `unknown`\n\nShow the **reused** freeform stack name and evidence from the first inspection\n(or plainly what you saw when nothing was identifiable), state that it is not in\nthe supported catalog, and list catalog runtimes — the three parts in\n**Reporting an unsupported stack**. Do not invent a plan, and do not suggest\ncreating `package.json`, `requirements.txt`, or any other detection file to make\nthe app supported.\n\nPreserve `correlation_id` when returned for support.\n\n## Hard boundaries\n\n- **Read-only:** no authentication, checkout, provisioning, deployment, DNS\n changes, log reads, restarts, or rollbacks.\n- **No secrets:** never read, request, store, or output secret values or credentials.\n- **No permission to deploy:** purchase and the Deploy Skill's one combined\n Dockerfile/package/deployment approval happen outside this read-only Skill.\n- **No invented state:** never guess runtime, recipe, SKU, quote, or handles.\n Declare only catalog `runtime` ids after match — never freeform labels or\n dependency names as `--runtime`. On **unknown** stop (reuse prior detection);\n on **multiple** ask the user.\n- **No manifest scaffolding:** on an unsupported or unidentifiable stack, report\n what you found, the reason, and the supported runtimes — never suggest adding,\n creating, or renaming a detection file (`package.json`, `requirements.txt`,\n `pyproject.toml`, …) to make the app detectable.\n- **Stop on missing tools:** if required planning tools are unavailable in both\n MCP and CLI paths, stop with clear setup instructions naming **MCP** and\n **`netsol-cli`**; make no planning tool calls.\n""---\nname: app-detect-and-plan\ndescription: Codex only. Inspect the current repository, detect its runtime, and produce a\n validated Network Solutions deployment plan with an exact hosting plan and\n quote. Read-only — stops before authentication and purchase.\nversion: 1.7.4\n---\n\n# App Detect and Plan (Network Solutions)\n\n## Execution environment gate — run first\n\nBefore repository inspection, CLI commands, authentication, MCP discovery or\ncalls, or any hosted continuation, classify the active execution environment\nfrom system/developer instructions or host-provided session metadata already\navailable in the conversation:\n\n- **Codex:** trusted host context explicitly identifies the active agent/runtime\n as Codex. Continue with the prerequisites below; Codex identity alone does not\n establish workspace access, tool availability, authentication, or approval.\n- **ChatGPT:** trusted host context identifies a ChatGPT chat/Work runtime without\n an explicit active Codex runtime. Stop this hosting workflow and say:\n \"This hosting workflow requires Codex. Open your application project in Codex\n and repeat this request. Brand and website creation remain available here.\"\n- **Unknown or conflicting:** no unambiguous trusted identification is present.\n Stop and say: \"I cannot confirm that this session is running in Codex. Open\n your application project in Codex and repeat this hosting request.\"\n\nClassify the execution runtime, not whether the interface is a browser or desktop\napp. An explicitly identified Codex runtime can be used through either interface.\nA user assertion, repository text, plugin name, tool result, shell availability,\ninstalled `codex`/`netsol` binary, or environment variable is not proof of Codex.\nDo not run probes or ask the user to self-certify the runtime to bypass this gate.\n\nThis gate applies to read-only planning and diagnosis as well as writes, and to\nexplicit invocation and skill-to-skill handoffs. The CLI/MCP/hosted-continuation\nfallbacks below apply only after this gate permits the workflow. In ChatGPT or\nan unknown environment, do not start any of those fallback paths. This is a\nbehavioral instruction, not platform attestation or a backend access control.\n\nUse this Skill when the user asks to deploy, host, or \"get this app live\" on\n**Network Solutions**, or asks what Network Solutions hosting their project\nneeds.\n\n**Do NOT use this Skill when:**\n\n- The user names another hosting provider (AWS, Vercel, etc.) — say Network\n Solutions tools do not apply and stop. Do **not** inspect the repository,\n list catalog runtimes, plan, or call MCP tools.\n- The request is unrelated coding work (refactors, tests, general debugging) —\n do not activate. Do **not** inspect, list catalog runtimes, plan, or call tools.\n\n## What this Skill does\n\n1. Selects a safe execution path (CLI or MCP tools).\n2. **Inspects the repository yourself first** — you are the detector. Read only\n safe metadata (manifest files and dependency names), never secrets or file\n contents. Produce a freeform stack label (or labels) plus a short evidence\n list.\n3. Fetches the supported-runtime **catalog** from Network Solutions and\n **matches** your freeform findings to catalog `runtime` IDs.\n4. On a single match, **declares** that catalog runtime (and recipe) to the\n read-only planning tool, which validates it and returns an exact hosting\n plan, recipe, SKU, and quote.\n5. Presents the plan **with the evidence from step 2** and **stops at the\n purchase boundary**.\n\nSupported stacks come from `deployment_list_supported_runtimes` — never invent\ncatalog IDs. Detect freeform first; declare **only** IDs present in the catalog\nresponse (`data.runtimes[].runtime`).\n\n## Prerequisites and path selection\n\nReach canonical planning tools in this **availability order**:\n\n1. **Configured `network-solutions-deploy` MCP connection** (public gateway tools).\n2. **`netsol-cli`** (≥0.2.0) when installed and compatible.\n3. **Trusted Network Solutions hosted continuation** when offered to the user.\n\nIf none of the three is available, tell the user how to add the MCP server or\nrun `npm i -g @network-solutions/cli` so `netsol` is on PATH and use `npx netsol`, and stop. Never substitute a private endpoint, demo tool,\nor guessed plan.\n\nWhen the CLI path is intended, do not run a separate Node/npm version preflight before the bootstrap below. If `npm` or `npx` is unavailable, or `npx netsol version` / global CLI install fails because of Node or npm version limits, give Node.js LTS (>= 22.12) install guidance, stop, and wait for user confirmation.\n\n**CLI bootstrap (strict order):** Run each step as a **separate** shell command — do not chain the version probe with repository scans, `command -v`, bare `netsol version`, or install.\n\n1. Probe first:\n\n```bash\nnpx netsol version\n```\n\n2. **Only if** step 1 fails because the CLI is not installed, install globally, then retry:\n\n```bash\nnpm i -g @network-solutions/cli\nnpx netsol version\n```\n\n(Alternatively: `pnpm add -g @network-solutions/cli` or `bun add -g @network-solutions/cli` when the user uses those package managers.)\n\nDo **not** run `npm i -g @network-solutions/cli` (or any install) until step 1 has been attempted. Do **not** use `command -v netsol` or bare `netsol version` **instead of** the first `npx netsol version` probe.\n\nRequire `data.cli_version` >= `0.2.0` from the version event.\n\n**CLI install anti-patterns:** Do not run `npm install --prefix` to `/tmp`, `/private/tmp`, or any side directory. Do not invoke `node_modules/.bin/netsol` by absolute path. Do not install before the `npx netsol version` probe.\n\nWorkflow steps in this skill use **`npx netsol …`**.\n\nPlanning does not require MCP OAuth. When the CLI path is intended, do not run\n**`codex mcp login`** before plan — use **`npx netsol capabilities plan`** after\ncatalog match (public plan steps need no login).\n\n### Use-case routing (when multiple paths are available)\n\n| Use case | Prefer | Why |\n| --- | --- | --- |\n| Full read-only plan | Inspect + catalog match, then `npx netsol capabilities plan [path] --runtime <catalog-id> [--recipe-id <id>]` | Detect first; pass a catalog id; CLI re-validates against the catalog |\n| MCP available but CLI missing | MCP tools (Path B below) | Detect first; fetch catalog; declare a catalog ID |\n| Both MCP and CLI available | **CLI for planning** after catalog match; MCP only if CLI is missing or fails with \"command not found\" | CLI re-validates your declaration |\n\nNever call tools excluded from the compatibility baseline (see\n`netsol-cli/contracts/compatibility/README.md`) or any write, purchase, auth,\ndeploy, DNS, log, or rollback tool from this Skill.\n\n---\n\n## Detecting the runtime (detect first, then catalog)\n\nOrder matters:\n\n1. **Inspect the repository** at its root **before** fetching the catalog.\n2. Run a **preflight inspect** (manifest-first; evidence = files present, not\n framework brands):\n 1. **Choose project root** — repo root, or the user-selected package\n directory in a monorepo.\n 2. **Monorepo markers** (when at repo root): `turbo.json`,\n `pnpm-workspace.yaml`, `lerna.json`, or `workspaces` in root `package.json`\n → **ask which package root** to deploy before planning. Until the user\n chooses a package root, do **not** assign a stack label from nested paths\n such as `apps/web/package.json`.\n 3. **Strong signals at the chosen root:**\n - **Node.js** — `package.json` exists (evidence: lockfile if present —\n `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`; optional\n `scripts.start` or `main`). Use the short freeform label **`Node.js`**\n (not “Node.js application”) — do not infer or name a framework brand.\n - **FastAPI** — `fastapi` appears in `requirements.txt` or\n `pyproject.toml`. Use the short freeform label **`FastAPI`**.\n - **Other stacks** (Ruby, Django, Java, …) — name them from safe metadata\n only with short labels such as **`Ruby`**, **`Java/Maven`** (e.g. Ruby\n from `main.rb` / `Gemfile`; Java/Maven from `pom.xml`).\n 4. Produce **freeform** stack label(s) and a short **evidence list**. Copy\n evidence strings **verbatim** from the repository inventory (e.g.\n `package.json: root manifest`, not paraphrases like “root package.json\n manifest”).\n3. **Then** obtain the catalog and **match** freeform findings to catalog\n `runtime` IDs (see **Catalog id vs freeform** below).\n\nRules:\n\n- Read manifest files and dependency **names** only. Never open `.env`, keys,\n or credentials; never read source bytes, versions, or secret values. When\n `.env` is listed in the repository inventory, add a `refuse_secret_access`\n step, set secret refusal flags, and **omit every `.env` line from the evidence\n list** — evidence stays limited to safe manifest entries only (e.g.\n `package.json: root manifest`).\n- A `Dockerfile`, `Procfile`, `docker-compose.yml`, or CI config is **not** a\n supported runtime signal. A repository that contains only those is a\n container-only repo — that is an **unknown** outcome, not a match.\n- After a **valid catalog plan**, the Deploy skill may create a root `Dockerfile`\n for image build and record local user consent under\n `.networksolutions/dockerfile.json`. That is a post-plan packaging step — it\n does **not** change detection rules and must **not** be suggested here as a\n way to force an unsupported stack to match.\n- After the catalog match, decide exactly one outcome:\n - **one match** — declare that catalog runtime (e.g. `nodejs`, `fastapi`) via\n Path A or Path B. Only the **plan/recommend** step carries the declared\n catalog runtime; inspection, catalog listing, and user-choice prompts do\n **not** declare a runtime yet.\n - **unknown** — zero catalog matches. Stop with `UNSUPPORTED_STACK`. No plan\n call; no best-effort deploy. See **Reporting an unsupported stack** below.\n - **multiple** — more than one catalog match (e.g. Node.js app with\n `package.json` and FastAPI backend) → ask which supported stack to deploy;\n do not guess and do not recommend a plan until the user chooses.\n\n### Reporting an unsupported stack\n\n**Reuse** the freeform stack + evidence from step 1 (no second detection pass)\nand give the developer exactly three things, then stop:\n\n1. **What you found** — the stack name with its evidence (e.g. \"Java/Maven via\n `pom.xml`\"). When step 1 identified nothing, say so plainly and name the\n files you did see (e.g. \"only a `Dockerfile`, no recognized runtime\n manifest\").\n2. **Why you cannot proceed** — that runtime is not in the Network Solutions\n supported-runtime catalog.\n3. **The supported runtimes** — from the catalog (`data.runtimes[].runtime`) or\n the error's `data.supported`. Include those catalog runtime ids (e.g.\n `nodejs`, `fastapi`) and the literal status `UNSUPPORTED_STACK` in the user\n message. Reuse prior evidence strings **verbatim** in the message.\n\n**Never suggest adding, creating, renaming, or scaffolding a detection file.**\nDo not tell the developer to add `package.json`, `requirements.txt`,\n`pyproject.toml`, or any other manifest so the app becomes detectable or\nsupported. Refuse scaffolding with the phrase **“Manifest scaffolding is\nrefused.”** without echoing filenames next to words like add, create, or\nscaffold (even when refusing a user request to add those files).\n\n### Catalog id vs freeform\n\nFreeform inspection evidence is **not** a valid `--runtime` / declare value.\n\n| Freeform evidence (inspect) | Catalog `runtime` id (declare / `--runtime`) |\n| --- | --- |\n| Short label `Node.js`; root `package.json` at chosen project root | `nodejs` |\n| Short label `FastAPI`; dependency / requirement name `fastapi` | `fastapi` |\n| Short label `Ruby` | (no catalog match → `UNSUPPORTED_STACK`) |\n| Short label `Java/Maven` | (no catalog match → `UNSUPPORTED_STACK`) |\n\nHard rules:\n\n- `--runtime` and MCP `runtime` must equal some `data.runtimes[].runtime` from\n the catalog.\n- **Never** pass a dependency name, display label, or framework brand as the\n catalog runtime (e.g. do not use a package name from `dependencies` as\n `--runtime`). Dependency name `fastapi` happens to match catalog id `fastapi`;\n any Node.js app maps to catalog id **`nodejs`**.\n- Do not invent ids. If the catalog has no match, that is **unknown** — stop.\n\n### Example — unsupported Ruby app\n\nAfter inspecting `main.rb` you already know the stack is Ruby. After the\ncatalog has no match, stop with a message like:\n\n> This looks like a **Ruby** application (`main.rb`). Network Solutions managed\n> deployment currently supports **nodejs** and **fastapi** only, so I can't\n> proceed. Supported runtimes: `nodejs`, `fastapi`.\n\n### Example — container-only or Java repository\n\nA repo with only a `Dockerfile` (or a Java/Maven service with `pom.xml`) has no\ncatalog match. Name what you saw, give the reason, list the catalog, and stop:\n\n> This repository has only a `Dockerfile` and no recognized runtime manifest, so\n> I can't identify a supported stack. Network Solutions managed deployment\n> currently supports **nodejs** and **fastapi** only. Status:\n> `UNSUPPORTED_STACK`.\n\nDo **not** append anything like \"add `package.json` or `requirements.txt` and I\ncan continue\".\n\n---\n\n## Path A — Preferred: `netsol-cli` (when installed, ≥0.2.0)\n\nComplete **inspect → catalog match → single catalog id** before planning.\n\n### A0. Catalog match (required before plan)\n\nPrefer obtaining the catalog so you see `data.runtimes` before declaring:\n\n```bash\nnpx netsol mcp call deployment_list_supported_runtimes\n```\n\n(Or call MCP `deployment_list_supported_runtimes` when the CLI path is not used\nfor that step.)\n\nThen map freeform findings to a catalog `runtime` id using **Catalog id vs\nfreeform**. On **unknown** or **multiple**, stop or ask — do **not** run\n`capabilities plan` yet.\n\n### A1. Plan — `npx netsol capabilities plan [path] --runtime <catalog-id> [--recipe-id <id>]`\n\nPass only the **catalog** runtime id from A0. `--recipe-id` is optional; when\nomitted the CLI derives it from the catalog entry.\n\n```bash\nnpx netsol capabilities plan [path] --runtime nodejs --recipe-id nodejs-npm-start\n```\n\nParse the NDJSON `plan_ready` event. On success (`status: ok` or `pending`),\npresent fields from `data` (see **Presentation checklist**). On\n`UNSUPPORTED_STACK` or `VALIDATION_ERROR`, stop — no best-effort deploy.\n\nThe CLI fetches the catalog again and re-validates your declaration, then calls\ncanonical gateway tools on your behalf. That internal fetch is fine and does\n**not** replace A0: you must still match and pass a real catalog id (never a\ndep or display name). You do not need to duplicate `deployment_recommend_plan`\nmanually when this command succeeds.\n\n---\n\n## Path B — Fallback: MCP tools (CLI unavailable)\n\nUse only these planning tools via the configured `network-solutions-deploy` MCP server:\n\n- `deployment_list_supported_runtimes`\n- `deployment_recommend_plan`\n- `deployment_validate_plan` (optional)\n- `deployment_get_recipe_requirements` (optional)\n\n### B1. Detect the runtime yourself (first)\n\nInspect the repository as described in **Detecting the runtime** above. Keep the\nfreeform label(s) and evidence list. Never authenticate, and never read `.env`,\nkeys, or credentials. Refuse secret access **only** when `.env` appears in the\nrepository inventory; otherwise do not add a secret-refusal step and do not set\nsecret refusal flags.\n\n### B2. Fetch the catalog (second)\n\nCall `deployment_list_supported_runtimes` and read `data.runtimes`: each entry\nhas `runtime`, `recipe`, `min_plan`, and build/start commands. Match your\nfreeform findings to these **catalog ids** (not dep names). On **unknown** or\n**multiple**, follow the outcomes above — do not call `deployment_recommend_plan`\nuntil there is exactly one chosen catalog runtime. Always list the catalog\nafter inspection, including when asking for a package root or runtime choice.\n\n### B3. Recommend plan (declare a catalog ID)\n\n```json\n{\"runtime\": \"nodejs\", \"recipe_id\": \"nodejs-npm-start\"}\n```\n\nCall `deployment_recommend_plan` with the matched catalog runtime (and\noptionally `recipe_id`). Record this planning step as **`recommend_plan`** —\nnever as `capabilities_plan` (CLI-only). You may include an optional `evidence_summary`\n(manifest files and dependency names) — it is audit-only and never changes the\nrecommendation. Never send `project_signals`; never send `repo_path` in\nproduction paths; never declare a freeform name or dep name that is not a\ncatalog `runtime` id.\n\n### B4. Optional enrichment\n\n- `deployment_validate_plan` with `deployment_plan_id` → `required_env_vars` (names only).\n- `deployment_get_recipe_requirements` with `recipe_id` → required files and env-var **names** (never values).\n\n---\n\n## Result interpretation\n\n| Result | Action |\n| --- | --- |\n| `status: requires_action` (or CLI `plan_ready` pending) | Valid plan exists — present checklist fields; save handles |\n| Agent-side `unknown` (no catalog match) | Reuse step-1 stack + evidence; give reason; list catalog; stop; never call recommend/plan; never suggest adding detection files |\n| `error_code: UNSUPPORTED_STACK` | Reuse step-1 detection if available; list `data.supported` if present; stop; never best-effort deploy; never suggest adding detection files |\n| `error_code: VALIDATION_ERROR` | Your declaration was rejected (unknown recipe or runtime/recipe mismatch) — report the literal `VALIDATION_ERROR`, list catalog runtime ids to recheck, and keep the catalog runtime id you attempted in your declared runtime; do not retry blindly |\n| Other errors | Report `summary` and `error_code`; retry once if `retryable` |\n\n## Presentation checklist\n\n### When invoked by Deploy to Network Solutions\n\nReturn plan, runtime, recipe, SKU, quote, evidence, commands, environment names,\nand workflow handles to the calling deployment workflow **internally**. Do not\npresent this section's standalone plan summary. The deploy workflow's stricter\nfour-field output contract overrides the presentation rules below. The\nuser-facing message for deploy-internal handoff must be **generic only** — never\ninclude runtime, recipe, SKU, quote reference, deployment plan id, workflow id,\nor any other plan fact value. Example:\n\n> A validated plan was returned internally to the calling deployment workflow;\n> user-facing deployment output remains controlled by that workflow.\n\n### On a successful plan\n\nBefore stopping, show the user:\n\n- **Runtime** and **recipe** (and `recipe_id` when returned)\n- **The evidence from local inspection** (manifest files, key dependency names)\n- **Build/start commands** when returned\n- **Plan name and SKU** (`data.product_requirement` or CLI `plan_ready` equivalent)\n- **Quote reference and expiry** (`quote_reference`, `quote_expires_at`)\n- **Required environment variable names** only (from validate/recipe tools)\n- **`workflow_id`** and **`deployment_plan_id`** from `state_handles` or CLI `plan_ready` data\n\nFinish with: \"To proceed, purchase/confirm the hosting plan — the Deploy to\nNetwork Solutions Skill continues from workflow `<workflow_id>`.\"\n\n### On `unknown`\n\nShow the **reused** freeform stack name and evidence from the first inspection\n(or plainly what you saw when nothing was identifiable), state that it is not in\nthe supported catalog, and list catalog runtimes — the three parts in\n**Reporting an unsupported stack**. Do not invent a plan, and do not suggest\ncreating `package.json`, `requirements.txt`, or any other detection file to make\nthe app supported.\n\nPreserve `correlation_id` when returned for support.\n\n## Hard boundaries\n\n- **Read-only:** no authentication, checkout, provisioning, deployment, DNS\n changes, log reads, restarts, or rollbacks.\n- **No secrets:** never read, request, store, or output secret values or credentials.\n- **No permission to deploy:** purchase and the Deploy Skill's one combined\n Dockerfile/package/deployment approval happen outside this read-only Skill.\n- **No invented state:** never guess runtime, recipe, SKU, quote, or handles.\n Declare only catalog `runtime` ids after match — never freeform labels or\n dependency names as `--runtime`. On **unknown** stop (reuse prior detection);\n on **multiple** ask the user.\n- **No manifest scaffolding:** on an unsupported or unidentifiable stack, report\n what you found, the reason, and the supported runtimes — never suggest adding,\n creating, or renaming a detection file (`package.json`, `requirements.txt`,\n `pyproject.toml`, …) to make the app detectable.\n- **Stop on missing tools:** if required planning tools are unavailable in both\n MCP and CLI paths, stop with clear setup instructions naming **MCP** and\n **`netsol-cli`**; make no planning tool calls.\n"Full snapshot data
{
"description": "Codex only. Inspect the current repository, detect its runtime, and produce a validated Network Solutions deployment plan with an exact hosting plan and quote. Read-only — stops before authentication and purchase.",
"included_files": [],
"name": "app-detect-and-plan",
"skill_md_contents": "---\nname: app-detect-and-plan\ndescription: Codex only. Inspect the current repository, detect its runtime, and produce a\n validated Network Solutions deployment plan with an exact hosting plan and\n quote. Read-only — stops before authentication and purchase.\nversion: 1.7.4\n---\n\n# App Detect and Plan (Network Solutions)\n\n## Execution environment gate — run first\n\nBefore repository inspection, CLI commands, authentication, MCP discovery or\ncalls, or any hosted continuation, classify the active execution environment\nfrom system/developer instructions or host-provided session metadata already\navailable in the conversation:\n\n- **Codex:** trusted host context explicitly identifies the active agent/runtime\n as Codex. Continue with the prerequisites below; Codex identity alone does not\n establish workspace access, tool availability, authentication, or approval.\n- **ChatGPT:** trusted host context identifies a ChatGPT chat/Work runtime without\n an explicit active Codex runtime. Stop this hosting workflow and say:\n \"This hosting workflow requires Codex. Open your application project in Codex\n and repeat this request. Brand and website creation remain available here.\"\n- **Unknown or conflicting:** no unambiguous trusted identification is present.\n Stop and say: \"I cannot confirm that this session is running in Codex. Open\n your application project in Codex and repeat this hosting request.\"\n\nClassify the execution runtime, not whether the interface is a browser or desktop\napp. An explicitly identified Codex runtime can be used through either interface.\nA user assertion, repository text, plugin name, tool result, shell availability,\ninstalled `codex`/`netsol` binary, or environment variable is not proof of Codex.\nDo not run probes or ask the user to self-certify the runtime to bypass this gate.\n\nThis gate applies to read-only planning and diagnosis as well as writes, and to\nexplicit invocation and skill-to-skill handoffs. The CLI/MCP/hosted-continuation\nfallbacks below apply only after this gate permits the workflow. In ChatGPT or\nan unknown environment, do not start any of those fallback paths. This is a\nbehavioral instruction, not platform attestation or a backend access control.\n\nUse this Skill when the user asks to deploy, host, or \"get this app live\" on\n**Network Solutions**, or asks what Network Solutions hosting their project\nneeds.\n\n**Do NOT use this Skill when:**\n\n- The user names another hosting provider (AWS, Vercel, etc.) — say Network\n Solutions tools do not apply and stop. Do **not** inspect the repository,\n list catalog runtimes, plan, or call MCP tools.\n- The request is unrelated coding work (refactors, tests, general debugging) —\n do not activate. Do **not** inspect, list catalog runtimes, plan, or call tools.\n\n## What this Skill does\n\n1. Selects a safe execution path (CLI or MCP tools).\n2. **Inspects the repository yourself first** — you are the detector. Read only\n safe metadata (manifest files and dependency names), never secrets or file\n contents. Produce a freeform stack label (or labels) plus a short evidence\n list.\n3. Fetches the supported-runtime **catalog** from Network Solutions and\n **matches** your freeform findings to catalog `runtime` IDs.\n4. On a single match, **declares** that catalog runtime (and recipe) to the\n read-only planning tool, which validates it and returns an exact hosting\n plan, recipe, SKU, and quote.\n5. Presents the plan **with the evidence from step 2** and **stops at the\n purchase boundary**.\n\nSupported stacks come from `deployment_list_supported_runtimes` — never invent\ncatalog IDs. Detect freeform first; declare **only** IDs present in the catalog\nresponse (`data.runtimes[].runtime`).\n\n## Prerequisites and path selection\n\nReach canonical planning tools in this **availability order**:\n\n1. **Configured `network-solutions-deploy` MCP connection** (public gateway tools).\n2. **`netsol-cli`** (≥0.2.0) when installed and compatible.\n3. **Trusted Network Solutions hosted continuation** when offered to the user.\n\nIf none of the three is available, tell the user how to add the MCP server or\nrun `npm i -g @network-solutions/cli` so `netsol` is on PATH and use `npx netsol`, and stop. Never substitute a private endpoint, demo tool,\nor guessed plan.\n\nWhen the CLI path is intended, do not run a separate Node/npm version preflight before the bootstrap below. If `npm` or `npx` is unavailable, or `npx netsol version` / global CLI install fails because of Node or npm version limits, give Node.js LTS (>= 22.12) install guidance, stop, and wait for user confirmation.\n\n**CLI bootstrap (strict order):** Run each step as a **separate** shell command — do not chain the version probe with repository scans, `command -v`, bare `netsol version`, or install.\n\n1. Probe first:\n\n```bash\nnpx netsol version\n```\n\n2. **Only if** step 1 fails because the CLI is not installed, install globally, then retry:\n\n```bash\nnpm i -g @network-solutions/cli\nnpx netsol version\n```\n\n(Alternatively: `pnpm add -g @network-solutions/cli` or `bun add -g @network-solutions/cli` when the user uses those package managers.)\n\nDo **not** run `npm i -g @network-solutions/cli` (or any install) until step 1 has been attempted. Do **not** use `command -v netsol` or bare `netsol version` **instead of** the first `npx netsol version` probe.\n\nRequire `data.cli_version` >= `0.2.0` from the version event.\n\n**CLI install anti-patterns:** Do not run `npm install --prefix` to `/tmp`, `/private/tmp`, or any side directory. Do not invoke `node_modules/.bin/netsol` by absolute path. Do not install before the `npx netsol version` probe.\n\nWorkflow steps in this skill use **`npx netsol …`**.\n\nPlanning does not require MCP OAuth. When the CLI path is intended, do not run\n**`codex mcp login`** before plan — use **`npx netsol capabilities plan`** after\ncatalog match (public plan steps need no login).\n\n### Use-case routing (when multiple paths are available)\n\n| Use case | Prefer | Why |\n| --- | --- | --- |\n| Full read-only plan | Inspect + catalog match, then `npx netsol capabilities plan [path] --runtime <catalog-id> [--recipe-id <id>]` | Detect first; pass a catalog id; CLI re-validates against the catalog |\n| MCP available but CLI missing | MCP tools (Path B below) | Detect first; fetch catalog; declare a catalog ID |\n| Both MCP and CLI available | **CLI for planning** after catalog match; MCP only if CLI is missing or fails with \"command not found\" | CLI re-validates your declaration |\n\nNever call tools excluded from the compatibility baseline (see\n`netsol-cli/contracts/compatibility/README.md`) or any write, purchase, auth,\ndeploy, DNS, log, or rollback tool from this Skill.\n\n---\n\n## Detecting the runtime (detect first, then catalog)\n\nOrder matters:\n\n1. **Inspect the repository** at its root **before** fetching the catalog.\n2. Run a **preflight inspect** (manifest-first; evidence = files present, not\n framework brands):\n 1. **Choose project root** — repo root, or the user-selected package\n directory in a monorepo.\n 2. **Monorepo markers** (when at repo root): `turbo.json`,\n `pnpm-workspace.yaml`, `lerna.json`, or `workspaces` in root `package.json`\n → **ask which package root** to deploy before planning. Until the user\n chooses a package root, do **not** assign a stack label from nested paths\n such as `apps/web/package.json`.\n 3. **Strong signals at the chosen root:**\n - **Node.js** — `package.json` exists (evidence: lockfile if present —\n `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`; optional\n `scripts.start` or `main`). Use the short freeform label **`Node.js`**\n (not “Node.js application”) — do not infer or name a framework brand.\n - **FastAPI** — `fastapi` appears in `requirements.txt` or\n `pyproject.toml`. Use the short freeform label **`FastAPI`**.\n - **Other stacks** (Ruby, Django, Java, …) — name them from safe metadata\n only with short labels such as **`Ruby`**, **`Java/Maven`** (e.g. Ruby\n from `main.rb` / `Gemfile`; Java/Maven from `pom.xml`).\n 4. Produce **freeform** stack label(s) and a short **evidence list**. Copy\n evidence strings **verbatim** from the repository inventory (e.g.\n `package.json: root manifest`, not paraphrases like “root package.json\n manifest”).\n3. **Then** obtain the catalog and **match** freeform findings to catalog\n `runtime` IDs (see **Catalog id vs freeform** below).\n\nRules:\n\n- Read manifest files and dependency **names** only. Never open `.env`, keys,\n or credentials; never read source bytes, versions, or secret values. When\n `.env` is listed in the repository inventory, add a `refuse_secret_access`\n step, set secret refusal flags, and **omit every `.env` line from the evidence\n list** — evidence stays limited to safe manifest entries only (e.g.\n `package.json: root manifest`).\n- A `Dockerfile`, `Procfile`, `docker-compose.yml`, or CI config is **not** a\n supported runtime signal. A repository that contains only those is a\n container-only repo — that is an **unknown** outcome, not a match.\n- After a **valid catalog plan**, the Deploy skill may create a root `Dockerfile`\n for image build and record local user consent under\n `.networksolutions/dockerfile.json`. That is a post-plan packaging step — it\n does **not** change detection rules and must **not** be suggested here as a\n way to force an unsupported stack to match.\n- After the catalog match, decide exactly one outcome:\n - **one match** — declare that catalog runtime (e.g. `nodejs`, `fastapi`) via\n Path A or Path B. Only the **plan/recommend** step carries the declared\n catalog runtime; inspection, catalog listing, and user-choice prompts do\n **not** declare a runtime yet.\n - **unknown** — zero catalog matches. Stop with `UNSUPPORTED_STACK`. No plan\n call; no best-effort deploy. See **Reporting an unsupported stack** below.\n - **multiple** — more than one catalog match (e.g. Node.js app with\n `package.json` and FastAPI backend) → ask which supported stack to deploy;\n do not guess and do not recommend a plan until the user chooses.\n\n### Reporting an unsupported stack\n\n**Reuse** the freeform stack + evidence from step 1 (no second detection pass)\nand give the developer exactly three things, then stop:\n\n1. **What you found** — the stack name with its evidence (e.g. \"Java/Maven via\n `pom.xml`\"). When step 1 identified nothing, say so plainly and name the\n files you did see (e.g. \"only a `Dockerfile`, no recognized runtime\n manifest\").\n2. **Why you cannot proceed** — that runtime is not in the Network Solutions\n supported-runtime catalog.\n3. **The supported runtimes** — from the catalog (`data.runtimes[].runtime`) or\n the error's `data.supported`. Include those catalog runtime ids (e.g.\n `nodejs`, `fastapi`) and the literal status `UNSUPPORTED_STACK` in the user\n message. Reuse prior evidence strings **verbatim** in the message.\n\n**Never suggest adding, creating, renaming, or scaffolding a detection file.**\nDo not tell the developer to add `package.json`, `requirements.txt`,\n`pyproject.toml`, or any other manifest so the app becomes detectable or\nsupported. Refuse scaffolding with the phrase **“Manifest scaffolding is\nrefused.”** without echoing filenames next to words like add, create, or\nscaffold (even when refusing a user request to add those files).\n\n### Catalog id vs freeform\n\nFreeform inspection evidence is **not** a valid `--runtime` / declare value.\n\n| Freeform evidence (inspect) | Catalog `runtime` id (declare / `--runtime`) |\n| --- | --- |\n| Short label `Node.js`; root `package.json` at chosen project root | `nodejs` |\n| Short label `FastAPI`; dependency / requirement name `fastapi` | `fastapi` |\n| Short label `Ruby` | (no catalog match → `UNSUPPORTED_STACK`) |\n| Short label `Java/Maven` | (no catalog match → `UNSUPPORTED_STACK`) |\n\nHard rules:\n\n- `--runtime` and MCP `runtime` must equal some `data.runtimes[].runtime` from\n the catalog.\n- **Never** pass a dependency name, display label, or framework brand as the\n catalog runtime (e.g. do not use a package name from `dependencies` as\n `--runtime`). Dependency name `fastapi` happens to match catalog id `fastapi`;\n any Node.js app maps to catalog id **`nodejs`**.\n- Do not invent ids. If the catalog has no match, that is **unknown** — stop.\n\n### Example — unsupported Ruby app\n\nAfter inspecting `main.rb` you already know the stack is Ruby. After the\ncatalog has no match, stop with a message like:\n\n> This looks like a **Ruby** application (`main.rb`). Network Solutions managed\n> deployment currently supports **nodejs** and **fastapi** only, so I can't\n> proceed. Supported runtimes: `nodejs`, `fastapi`.\n\n### Example — container-only or Java repository\n\nA repo with only a `Dockerfile` (or a Java/Maven service with `pom.xml`) has no\ncatalog match. Name what you saw, give the reason, list the catalog, and stop:\n\n> This repository has only a `Dockerfile` and no recognized runtime manifest, so\n> I can't identify a supported stack. Network Solutions managed deployment\n> currently supports **nodejs** and **fastapi** only. Status:\n> `UNSUPPORTED_STACK`.\n\nDo **not** append anything like \"add `package.json` or `requirements.txt` and I\ncan continue\".\n\n---\n\n## Path A — Preferred: `netsol-cli` (when installed, ≥0.2.0)\n\nComplete **inspect → catalog match → single catalog id** before planning.\n\n### A0. Catalog match (required before plan)\n\nPrefer obtaining the catalog so you see `data.runtimes` before declaring:\n\n```bash\nnpx netsol mcp call deployment_list_supported_runtimes\n```\n\n(Or call MCP `deployment_list_supported_runtimes` when the CLI path is not used\nfor that step.)\n\nThen map freeform findings to a catalog `runtime` id using **Catalog id vs\nfreeform**. On **unknown** or **multiple**, stop or ask — do **not** run\n`capabilities plan` yet.\n\n### A1. Plan — `npx netsol capabilities plan [path] --runtime <catalog-id> [--recipe-id <id>]`\n\nPass only the **catalog** runtime id from A0. `--recipe-id` is optional; when\nomitted the CLI derives it from the catalog entry.\n\n```bash\nnpx netsol capabilities plan [path] --runtime nodejs --recipe-id nodejs-npm-start\n```\n\nParse the NDJSON `plan_ready` event. On success (`status: ok` or `pending`),\npresent fields from `data` (see **Presentation checklist**). On\n`UNSUPPORTED_STACK` or `VALIDATION_ERROR`, stop — no best-effort deploy.\n\nThe CLI fetches the catalog again and re-validates your declaration, then calls\ncanonical gateway tools on your behalf. That internal fetch is fine and does\n**not** replace A0: you must still match and pass a real catalog id (never a\ndep or display name). You do not need to duplicate `deployment_recommend_plan`\nmanually when this command succeeds.\n\n---\n\n## Path B — Fallback: MCP tools (CLI unavailable)\n\nUse only these planning tools via the configured `network-solutions-deploy` MCP server:\n\n- `deployment_list_supported_runtimes`\n- `deployment_recommend_plan`\n- `deployment_validate_plan` (optional)\n- `deployment_get_recipe_requirements` (optional)\n\n### B1. Detect the runtime yourself (first)\n\nInspect the repository as described in **Detecting the runtime** above. Keep the\nfreeform label(s) and evidence list. Never authenticate, and never read `.env`,\nkeys, or credentials. Refuse secret access **only** when `.env` appears in the\nrepository inventory; otherwise do not add a secret-refusal step and do not set\nsecret refusal flags.\n\n### B2. Fetch the catalog (second)\n\nCall `deployment_list_supported_runtimes` and read `data.runtimes`: each entry\nhas `runtime`, `recipe`, `min_plan`, and build/start commands. Match your\nfreeform findings to these **catalog ids** (not dep names). On **unknown** or\n**multiple**, follow the outcomes above — do not call `deployment_recommend_plan`\nuntil there is exactly one chosen catalog runtime. Always list the catalog\nafter inspection, including when asking for a package root or runtime choice.\n\n### B3. Recommend plan (declare a catalog ID)\n\n```json\n{\"runtime\": \"nodejs\", \"recipe_id\": \"nodejs-npm-start\"}\n```\n\nCall `deployment_recommend_plan` with the matched catalog runtime (and\noptionally `recipe_id`). Record this planning step as **`recommend_plan`** —\nnever as `capabilities_plan` (CLI-only). You may include an optional `evidence_summary`\n(manifest files and dependency names) — it is audit-only and never changes the\nrecommendation. Never send `project_signals`; never send `repo_path` in\nproduction paths; never declare a freeform name or dep name that is not a\ncatalog `runtime` id.\n\n### B4. Optional enrichment\n\n- `deployment_validate_plan` with `deployment_plan_id` → `required_env_vars` (names only).\n- `deployment_get_recipe_requirements` with `recipe_id` → required files and env-var **names** (never values).\n\n---\n\n## Result interpretation\n\n| Result | Action |\n| --- | --- |\n| `status: requires_action` (or CLI `plan_ready` pending) | Valid plan exists — present checklist fields; save handles |\n| Agent-side `unknown` (no catalog match) | Reuse step-1 stack + evidence; give reason; list catalog; stop; never call recommend/plan; never suggest adding detection files |\n| `error_code: UNSUPPORTED_STACK` | Reuse step-1 detection if available; list `data.supported` if present; stop; never best-effort deploy; never suggest adding detection files |\n| `error_code: VALIDATION_ERROR` | Your declaration was rejected (unknown recipe or runtime/recipe mismatch) — report the literal `VALIDATION_ERROR`, list catalog runtime ids to recheck, and keep the catalog runtime id you attempted in your declared runtime; do not retry blindly |\n| Other errors | Report `summary` and `error_code`; retry once if `retryable` |\n\n## Presentation checklist\n\n### When invoked by Deploy to Network Solutions\n\nReturn plan, runtime, recipe, SKU, quote, evidence, commands, environment names,\nand workflow handles to the calling deployment workflow **internally**. Do not\npresent this section's standalone plan summary. The deploy workflow's stricter\nfour-field output contract overrides the presentation rules below. The\nuser-facing message for deploy-internal handoff must be **generic only** — never\ninclude runtime, recipe, SKU, quote reference, deployment plan id, workflow id,\nor any other plan fact value. Example:\n\n> A validated plan was returned internally to the calling deployment workflow;\n> user-facing deployment output remains controlled by that workflow.\n\n### On a successful plan\n\nBefore stopping, show the user:\n\n- **Runtime** and **recipe** (and `recipe_id` when returned)\n- **The evidence from local inspection** (manifest files, key dependency names)\n- **Build/start commands** when returned\n- **Plan name and SKU** (`data.product_requirement` or CLI `plan_ready` equivalent)\n- **Quote reference and expiry** (`quote_reference`, `quote_expires_at`)\n- **Required environment variable names** only (from validate/recipe tools)\n- **`workflow_id`** and **`deployment_plan_id`** from `state_handles` or CLI `plan_ready` data\n\nFinish with: \"To proceed, purchase/confirm the hosting plan — the Deploy to\nNetwork Solutions Skill continues from workflow `<workflow_id>`.\"\n\n### On `unknown`\n\nShow the **reused** freeform stack name and evidence from the first inspection\n(or plainly what you saw when nothing was identifiable), state that it is not in\nthe supported catalog, and list catalog runtimes — the three parts in\n**Reporting an unsupported stack**. Do not invent a plan, and do not suggest\ncreating `package.json`, `requirements.txt`, or any other detection file to make\nthe app supported.\n\nPreserve `correlation_id` when returned for support.\n\n## Hard boundaries\n\n- **Read-only:** no authentication, checkout, provisioning, deployment, DNS\n changes, log reads, restarts, or rollbacks.\n- **No secrets:** never read, request, store, or output secret values or credentials.\n- **No permission to deploy:** purchase and the Deploy Skill's one combined\n Dockerfile/package/deployment approval happen outside this read-only Skill.\n- **No invented state:** never guess runtime, recipe, SKU, quote, or handles.\n Declare only catalog `runtime` ids after match — never freeform labels or\n dependency names as `--runtime`. On **unknown** stop (reuse prior detection);\n on **multiple** ask the user.\n- **No manifest scaffolding:** on an unsupported or unidentifiable stack, report\n what you found, the reason, and the supported runtimes — never suggest adding,\n creating, or renaming a detection file (`package.json`, `requirements.txt`,\n `pyproject.toml`, …) to make the app detectable.\n- **Stop on missing tools:** if required planning tools are unavailable in both\n MCP and CLI paths, stop with clear setup instructions naming **MCP** and\n **`netsol-cli`**; make no planning tool calls.\n"
}SHA-256 of public snapshot: d186001b1f9b6faa6d4a22da4e84f9198cba9cefe129fc1a0be55cefbb2fd37d