# misc


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

## read_pdf

Extract plain text from a PDF over a 1-indexed page range (via PyMuPDF)
– e.g. to let an LLM read a paper. Paths go through
`nbtools._resolve_safe`, so the sandbox setting applies here too.

------------------------------------------------------------------------

<a
href="https://github.com/drscotthawley/slmn/blob/main/slmn/misc.py#L17"
target="_blank" style="float:right; font-size:smaller">source</a>

### read_pdf

``` python
def read_pdf(
    path:str, # path to the PDF file
    start_page:int, # first page to extract, 1-indexed
    end_page:int, # last page to extract, inclusive
)->str:
```

*Extract plain text from a PDF file, by 1-indexed page range.*

## gpu_free

Is a local GPU actually free for compute? Tries `nvidia-smi`, falls back
to checking `/dev/nvidia*` with `fuser` (works on some WSL setups where
`nvidia-smi` is absent), and if there’s no GPU tooling at all, assumes
free. Returns `{'free': bool, 'detail': str}`.

------------------------------------------------------------------------

<a
href="https://github.com/drscotthawley/slmn/blob/main/slmn/misc.py#L30"
target="_blank" style="float:right; font-size:smaller">source</a>

### gpu_free

``` python
def gpu_free(
    gpu_idx:int=0, # which GPU to check
    busy_threshold_mib:int=2000, # VRAM usage (MiB) below which the GPU still counts as free
)->dict:
```

*Check whether a local GPU is free for compute. Tries nvidia-smi first;
falls back to checking /dev/nvidia* via fuser (works on some WSL
setups); if neither is available, assumes free. Returns {‘free’: bool,
‘detail’: str}.\*

## Installing skills

[`install_skills`](https://drscotthawley.github.io/slmn/misc.html#install_skills)
copies slmn’s packaged Claude Code skills (the
`slmn/skills/<name>/SKILL.md` dirs, shipped as package data) into a
`.claude/skills` directory so an agent can discover them – into the
current project by default, or the user-level `~/.claude/skills` with
`user=True`. Already-installed skills are skipped unless `force=True`,
so local edits survive.

------------------------------------------------------------------------

<a
href="https://github.com/drscotthawley/slmn/blob/main/slmn/misc.py#L63"
target="_blank" style="float:right; font-size:smaller">source</a>

### install_skills

``` python
def install_skills(
    dest:str=None, # directory to install into; defaults to '.claude/skills' under the current dir (or '~/.claude/skills' when user=True)
    user:bool=False, # install into the user-level '~/.claude/skills' instead of the current project's '.claude/skills'
    force:bool=False, # overwrite a skill that's already installed (default: skip it, so hand-edits to an installed skill aren't clobbered)
)->str:
```

*Copy slmn’s packaged Claude Code skills – the
slmn/skills/<name>/SKILL.md dirs shipped as package data – into a
`.claude/skills` directory so an agent (Claude Code, etc.) can discover
them. Installs into the current project by default; pass user=True for
the user-level dir, or an explicit `dest`. Each skill is copied as its
own <name>/ subdir; existing ones are skipped unless force=True. Returns
a short report of what was installed vs skipped.*
