## TL;DR
The kernelspec's `argv` still names the deleted conda env's Python, so every spawn attempt fails instantly and the launcher retries forever: a spawn loop with the kernel never reaching ready. Delete the stale kernelspec, then register a fresh one from the replacement environment's Python. Verify the new kernel reaches ready with a quick console session before handing it to any agent or scheduler.

```text
agent's kernelspec pointed at a deleted conda env: spawn loop, never ready
```

## Use this when
- A kernel shows as starting or connecting forever and never becomes ready.
- Logs show repeated spawn attempts failing on a Python path inside a removed conda env.
- An old conda env was deleted with `conda env remove` but its kernel entry remains.

## Not for this skill when
- The kernel starts and then dies importing packages. That is an environment-content problem.
- The kernel is not listed at all. That is a search-path problem, a different fix.

## Steps
1. Identify the stale spec: `jupyter kernelspec list` and read the suspect kernel.json's `argv`. Expected: the argv path contains the deleted env's directory.
2. Confirm the env is gone: check that the path does not exist. Expected: confirmed missing, so no repair of the env is possible.
3. Remove the stale spec: `jupyter kernelspec remove [kernel-name]`. Expected: the kernel disappears from the list.
4. Register the replacement: run `[new-env-python] -m ipykernel install --user --name [kernel-name] --display-name "[display]"` with the Python of the live environment. Expected: a fresh spec whose argv points at an existing interpreter.
5. Verify readiness directly: `jupyter console --kernel [kernel-name]` and execute a trivial expression. Expected: the kernel reaches ready and returns a result promptly.
6. If a scheduler or agent retries spawns, add a spawn-attempt cap so a future stale spec fails fast instead of looping. Expected: the launcher gives up with a clear error after N attempts.

## Tool compatibility
ipykernel 6.x; conda 23.x/24.x environments; jupyter_client 7.x/8.x; JupyterHub and single-user servers.

## Variant phrasings
### jupyter kernel spawn loop deleted conda env
The loop phrasing. Remove the stale spec and register the replacement env.

### kernel never ready after conda env removed
The readiness phrasing. The spec outlived the env; delete and re-register.

### kernelspec remove stale conda environment
The cleanup phrasing. Remove first, then install from the live interpreter.

## Why it happens
Conda env removal deletes the interpreter but knows nothing about Jupyter kernelspecs, which live in a separate directory tree. The spec keeps advertising a kernel whose executable is gone, and kernel launchers interpret a failed spawn as transient, so they retry with backoff forever instead of failing fast. From the user's side this looks like a kernel that is perpetually 'starting'. The loop is the launcher's optimism meeting a permanently broken spec; deleting the spec removes the false advertisement, and registering from a live env restores a kernel that can actually start.

## Edge cases / pitfalls
- Removing the spec while notebooks reference the kernel name leaves those notebooks pointing at nothing. Re-register under the same name to keep them working.
- JupyterHub may cache kernel lists; restart the single-user server after removing a stale spec.
- Agents that create and delete conda envs per run should manage kernelspecs in the same lifecycle: register on create, remove on delete.
- A spawn cap that is too aggressive can kill legitimate slow starts (large env imports). Set the cap generously and log each attempt.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_DxCfAd9qNzFp8SwyWRQgqg
