## TL;DR
The shared kernels directory is owned by root, so a non-root `ipykernel install` without `--user` dies on permission denied. Re-run the install with the `--user` flag, which writes the spec into your per-user Jupyter data directory where you always have write access. Then confirm the running server scans that user directory; if it does not, point the server at it rather than reaching for elevated privileges.

```text
installing kernelspec as non-root: permission denied on the shared kernels dir
```

## Use this when
- `python -m ipykernel install` fails with PermissionError or 'permission denied' naming a system kernels directory.
- You are on a shared machine, container, or CI runner where you cannot become root.
- The install works with elevated privileges but you need a non-privileged path.

## Not for this skill when
- The spec installs fine but the server cannot see it. That is a search-path mismatch, a different fix.
- The kernel installs and is visible but fails to launch. That is a broken spec or dead interpreter.

## Steps
1. Reproduce the exact failing command and note the directory in the error. Expected: the path is a system-level kernels directory you do not own.
2. Install to your user directory instead: `python -m ipykernel install --user --name [kernel-name] --display-name "[display]"`. Expected: install output confirms the spec landed under your user Jupyter data directory.
3. Verify visibility: `jupyter kernelspec list` as your user. Expected: the new kernel appears with a path under your home data directory.
4. Confirm the server will see it: run `jupyter --paths` in the server's context and check that your user data directory is on its list. Expected: the directory from step 2 is listed.
5. If the server runs as a different user (service account, container user), install the spec as THAT user or set its data directory accordingly instead of fighting permissions. Expected: the spec is owned by and visible to the server's user.
6. Launch a quick `jupyter console --kernel [kernel-name]` as the server user. Expected: a working prompt, proving the whole chain works without elevated privileges.

## Tool compatibility
ipykernel 6.x, jupyter_core 5.x, jupyter_client 7.x/8.x; Linux and macOS multi-user hosts, containers, CI runners.

## Variant phrasings
### ipykernel install permission denied
The short phrasing. Add --user to target the per-user kernels directory.

### cannot write to /usr/share/jupyter/kernels as non-root
The explicit-path phrasing. The user-level directory is the intended non-root target.

### jupyter kernelspec install without sudo
The how-to phrasing. --user is the supported answer; no sudo needed.

## Why it happens
Jupyter splits kernelspec storage into system, environment, and user levels, and the default `ipykernel install` targets the shared system location, which is root-owned on any sane multi-user machine. The `--user` flag exists precisely for this: it writes to the per-user data directory that Jupyter always includes in its search path for that user's servers. Reaching for elevated privileges to write a personal kernel spec is both unnecessary and a security smell on shared infrastructure. The only subtlety is that a server running as a different user has a different user directory, so the spec must be installed as the server's user, not yours.

## Edge cases / pitfalls
- On JupyterHub, `--user` installs into YOUR directory, which other users' single-user servers correctly cannot see. Per-user kernels are personal by design.
- Some minimal containers set HOME to a non-writable path. If `--user` still fails, check that HOME is writable before assuming a deeper problem.
- Mixing `--user` and `--sys-prefix` installs of the same kernel name creates shadowing. Pick one location per kernel name and remove the other.
- A spec installed with `--user` by root lands in root's home, invisible to everyone else. Install as the user that will run the server.

## Provenance

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