Metadata-Version: 2.4
Name: dspyteach
Version: 0.1.7b46
Summary: CLI utility that summarizes single files into teaching briefs using DSPy
Author: DSPy File Maintainers
Keywords: dspy,teaching,summaries,cli
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Operating System :: OS Independent
Classifier: Topic :: Software Development :: Code Generators
Requires-Python: <3.12,>=3.10
Description-Content-Type: text/markdown
Requires-Dist: dspy
Requires-Dist: pytest
Requires-Dist: python-dotenv

# dspyteach – DSPy File Teaching Analyzer

---

[![PyPI](https://img.shields.io/pypi/v/dspyteach.svg?include_prereleases&cacheSeconds=60&t=1)](https://pypi.org/project/dspyteach/)
[![Downloads](https://img.shields.io/pypi/dm/dspyteach.svg?cacheSeconds=300)](https://pypi.org/project/dspyteach/)
[![TestPyPI](https://img.shields.io/badge/TestPyPI-dspyteach-informational?cacheSeconds=300)](https://test.pypi.org/project/dspyteach/)
[![Release](https://github.com/AcidicSoil/dspy-file/actions/workflows/release.yml/badge.svg)](https://github.com/AcidicSoil/dspy-file/actions/workflows/release.yml)
[![Repo](https://img.shields.io/badge/GitHub-AcidicSoil%2Fdspy--file-181717?logo=github)](https://github.com/AcidicSoil/dspy-file)

---

## What it does

`dspyteach` is a Python CLI that analyzes one file or many files and generates either:

- a **teaching brief** (`--mode teach`, default), or
- a **refactor prompt template** (`--mode refactor`)

It supports:

- single files and recursive directory scans
- repeated include globs (`-g/--glob`)
- directory exclusions (`-ed/--exclude-dirs`)
- local providers such as **Ollama** and **LM Studio**
- OpenAI-compatible hosted endpoints
- mirrored output directory layouts when `--output-dir` is set

The package centers on:

- `dspy_file/analyze_file_cli.py` – CLI entrypoint and provider setup
- `dspy_file/file_analyzer.py` – teaching pipeline
- `dspy_file/refactor_analyzer.py` – refactor template pipeline
- `dspy_file/file_helpers.py` – file discovery, ignore rules, rendering
- `dspy_file/prompts/` – bundled refactor prompt templates

---

## Requirements

- Python `>=3.10,<3.12` (from `pyproject.toml`)
- a supported model backend:
  - **Ollama**
  - **LM Studio**
  - **OpenAI-compatible API**
- `uv` recommended for local development

---

## Install

### Local development

```bash
uv venv -p 3.11
source .venv/bin/activate
uv sync
```

### From PyPI

```bash
pip install dspyteach
```

Smoke check:

```bash
dspyteach --help
```

---

## Provider setup

### Ollama

Default provider is Ollama.

```bash
dspyteach path/to/file.md
```

The current default Ollama base URL is:

```text
http://localhost:11434
```

### LM Studio

LM Studio uses the OpenAI-compatible server at:

```text
http://localhost:1234/v1
```

Example:

```bash
dspyteach path/to/project \
  --provider lmstudio \
  --model qwen_qwen3-4b-instruct-2507 \
  --api-base http://localhost:1234/v1
```

More details:

- [LM Studio provider guide](docs/lm-studio-provider.md)

### Hosted OpenAI-compatible provider

```bash
dspyteach path/to/project \
  --provider openai \
  --model gpt-5 \
  --api-base https://your-endpoint.example/v1 \
  --api-key YOUR_KEY
```

---

## Environment variables

The CLI loads `.env` automatically via `python-dotenv`.

Common settings:

```env
DSPYTEACH_PROVIDER=ollama
DSPYTEACH_MODEL=hf.co/Mungert/osmosis-mcp-4b-GGUF:Q5_K_M
#DSPYTEACH_API_BASE=http://localhost:1234/v1
#DSPYTEACH_API_KEY=lm-studio
#OPENAI_API_KEY=
#DSPYTEACH_LOG_PATH=.dspyteach/logs/custom.log
#DSPYTEACH_MAX_TOKENS=4000
```

Notes:

- `DSPYTEACH_API_KEY` falls back to `OPENAI_API_KEY` when `DSPYTEACH_PROVIDER=openai`
- `DSPYTEACH_LOG_PATH` controls the runtime log file destination
- `DSPYTEACH_MAX_TOKENS` controls the root LM token budget used during DSPy configuration

See:

- [`.env.example`](.env.example)

---

## Usage

### Analyze a single file

```bash
dspyteach docs/example.md
```

### Analyze a directory recursively

```bash
dspyteach ./repo -g '**/*.py' -g '**/*.md'
```

### Write outputs to a separate mirrored tree

```bash
dspyteach ./repo \
  -g '**/*.md' \
  -o ./out
```

When `--output-dir` is set, the CLI mirrors the original relative directory layout inside the output directory and keeps the original filename.

### Skip directories while scanning

```bash
dspyteach ./repo \
  -g '**/*README*' \
  -g '**/package.json' \
  -g '**/pyproject.toml' \
  -ed '.git,node_modules,.venv,dist,build' \
  -o ./out
```

### Confirm each file before analysis

```bash
dspyteach ./repo -g '**/*.md' --confirm-each
```

### Print raw predictions

```bash
dspyteach docs/example.md --raw
```

---

## Globs

Include globs are **relative to the path you pass to `dspyteach`**.

Good:

```bash
dspyteach ../../../ai-apps \
  -g '**/README.md' \
  -g '**/package.json' \
  -g '**/pyproject.toml' \
  -o ../../../ai-apps/.readMes/.out
```

Not recommended:

```bash
# full absolute paths inside --glob are not needed
-g '~/projects/temp/ai-apps/**/README.md'
```

Repeat `-g` once per pattern.

---

## Modes

### Teach mode

Default mode. Generates a teaching-oriented markdown brief.

```bash
dspyteach path/to/file.md --mode teach
```

### Refactor mode

Generates a refactor-oriented prompt template.

```bash
dspyteach path/to/file.md --mode refactor
```

Refactor mode supports `-p/--prompt`:

```bash
dspyteach ./repo --mode refactor --prompt refactor_prompt_template
```

If multiple bundled templates are available and you do not pass `--prompt`, the CLI will prompt you to choose one.

---

## Output behavior

Current behavior:

- if `--output-dir` is **omitted**, the CLI writes output under `dspy_file/data/`
- if `--output-dir` is provided, the CLI writes into that directory and mirrors the source tree
- teaching mode appends `.teaching.md`; refactor mode appends `.refactor.md`
- `--in-place` requests source replacement, but real overwrites require per-file confirmation
- if `--in-place` is combined with `--output-dir`, the CLI writes the original filename into that directory instead of overwriting the source

This keeps the original source files unchanged unless you explicitly approve each overwrite.

Example:

```bash
dspyteach ../../../ai-apps \
  -m teach \
  -g '**/*README*' \
  -o ../../../ai-apps/.readMes/.out
```

---

## Logging

Runtime logging is configured once at the CLI boundary.

Default log path pattern:

```text
.dspyteach/logs/run-YYYYMMDD-HHMMSS-<pid>.log
```

Each CLI run now gets its own log file by default.

Override it with:

```env
DSPYTEACH_LOG_PATH=/absolute/path/to/dspyteach.log
```

The logger uses a rotating file handler.

## Run state, resume, and cleanup

Batch runs now persist resumable state under:

```text
.dspyteach/runs/<run_id>/
```

A saved run includes:

- `manifest.json` with run-level settings and status
- per-file checkpoint JSON files under `files/`
- stage data for teaching-mode resume, so cancelled files can continue from the last completed stage

By default, a fresh run gets a generated run id. You can also name one explicitly:

```bash
dspyteach ./repo -g '**/*.py' --run-id docs-pass-1
```

Resume a saved run:

```bash
dspyteach ./repo -g '**/*.py' --resume docs-pass-1
```

Resume validation is intentionally strict. The CLI expects the resumed run to match the original path, mode, provider/model settings, and scan filters.

### Inspect saved runs

List saved runs:

```bash
dspyteach --list-runs
```

Show one run and its per-file checkpoint stages:

```bash
dspyteach --show-run docs-pass-1
```

Machine-readable output is also available:

```bash
dspyteach --list-runs --json
dspyteach --show-run docs-pass-1 --json
```

### Delete or prune saved runs

Delete a single saved run:

```bash
dspyteach --delete-run docs-pass-1
```

Preview which runs would be pruned without deleting them:

```bash
dspyteach --prune-runs --prune-status failed --dry-run
```

Delete completed runs older than 14 days:

```bash
dspyteach --prune-runs --prune-status completed --prune-older-than-days 14
```

Preview prune results as JSON:

```bash
dspyteach --prune-runs \
  --prune-status failed,completed_with_errors \
  --prune-older-than-days 7 \
  --dry-run \
  --json
```

Pruning requires at least one filter:

- `--prune-status`
- `--prune-older-than-days`

This is intentional so pruning cannot accidentally behave like a delete-all command.

---

## Local model cleanup

Unless `--keep-provider-alive` is set, the CLI attempts to free local resources after the run:

- **Ollama** – stops the active model
- **LM Studio** – unloads matching loaded instances

```bash
dspyteach ./repo --provider lmstudio --keep-provider-alive
```

---

## Troubleshooting

- If Ollama cannot be reached, verify it is running on `http://localhost:11434`
- If LM Studio cannot be reached, verify the local server is running on `http://localhost:1234/v1`
- If you are scanning large trees, prefer `--output-dir` plus `--exclude-dirs`
- If one file fails during a batch, the CLI logs the exception and continues with the next file
- For debugging LM Studio integration, capture console output and inspect the runtime log file

Example verbose capture:

```bash
{ dspyteach ./repo -g '**/*.md'; } |& tee dspyteach.$(date +%Y%m%d-%H%M%S).log
```

---

## Releasing

Maintainer release steps live in:

- [docs/RELEASING.md](docs/RELEASING.md)

Tag workflow helper:

```bash
./scripts/tag-release.sh
```

Pushing a tag matching `v*` triggers:

- `.github/workflows/release.yml`

---

## Development notes

Targeted test runs used frequently in this repo:

```bash
uv run pytest -q
```

Focused examples:

```bash
uv run pytest -q tests/test_cli_connectivity.py
uv run pytest -q tests/test_file_helpers.py
uv run pytest -q tests/test_lmstudio_structured.py
```

---

## Example data

Sample generated outputs live under:

- [example-data](example-data/)
