Metadata-Version: 2.4
Name: dspyteach
Version: 0.2.1
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: python-dotenv
Requires-Dist: jsonschema
Requires-Dist: rich
Requires-Dist: typer
Requires-Dist: textual>=8.2.7

# 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 with three top-level workflows:

- `dspyteach analyze ...` for file-by-file DSPy analysis that generates:
  - a **teaching brief** (`--mode teach`, default),
  - a **refactor prompt template** (`--mode refactor`), or
  - direct **prompt-mode output** (`--mode prompt --prompt ...`)
- `dspyteach audit ...` for history-first prompt-library audits over mixed artifacts such as `.md`, `.json`, and `.jsonl`; `audit all` also writes repeated-query pattern and target-route artifacts after labeling
- `dspyteach todos scan ...` for TODO/FIXME/unfinished-work scans that produce agent-handoff lists

Use the explicit `analyze`, `audit`, or `todos` subcommand for every workflow.

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
- Rich-powered file-run progress bars with percentage, elapsed time, and ETA for recursive/bulk runs

The package centers on:

- `dspy_file/analyze_file_cli.py` – compatibility entrypoint used by packaging and tests
- `dspy_file/cli/` – grouped CLI parser, interaction, runner, and orchestration surface
- `dspy_file/analysis/` – grouped teaching, refactor, direct-prompt, validation, signatures, output, file-helper compatibility exports, and the Scan Source Module for deterministic source evidence records
- `dspy_file/infrastructure/` – grouped logging, run-state, provider-runtime, and LM Studio transport surface
- `dspy_file/audit_cli.py` – history-first audit command family and orchestration
- `dspy_file/history_audit/` – extractor, labeler, aggregator, coverage, and report stages
- `dspy_file/file_analyzer.py` – teaching pipeline and compatibility patch surface for tests
- `dspy_file/prompts/` – bundled prompt templates and prompt-loading helpers
- `ARCHITECTURE.md` – high-level codemap and module boundaries

---

## 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 checks:

```bash
dspyteach --help      # or: dspyteach -h
dspyteach --version   # or: dspyteach -V
dspyteach analyze --help
dspyteach analyze teach --help
dspyteach a t --help
dspyteach runs --help
dspyteach r ls --help
dspyteach audit --help
dspyteach todos scan --help
dspyteach config --help
```

---

## Provider setup

### Ollama

Default provider is Ollama.

```bash
dspyteach analyze 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 analyze 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 analyze 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=lmstudio
DSPYTEACH_MODEL=qwen_qwen3.5-4b
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
#DSPYTEACH_LM_TEMPERATURE=0.7
#DSPYTEACH_LM_TOP_P=0.95
#DSPYTEACH_LM_TOP_K=40
#DSPYTEACH_LM_MIN_P=0.05
#DSPYTEACH_LM_REASONING=off
#DSPYTEACH_LM_N_COMPLETIONS=1
#DSPYTEACH_LM_MAX_TOKENS=16000
#DSPYTEACH_LM_STOP=END,STOP
#DSPYTEACH_LM_PRESENCE_PENALTY=0.0
#DSPYTEACH_LM_FREQUENCY_PENALTY=0.0
#DSPYTEACH_LM_REPEAT_PENALTY=1.1
#DSPYTEACH_PROMPT_MAX_TOKENS=16000
#DSPYTEACH_PROMPT_MIN_WORDS=2500
#DSPYTEACH_PROMPT_EVIDENCE_MIN_CHARS=24000
#DSPYTEACH_PROMPT_CHUNK_CHARS=12000
#DSPYTEACH_PROMPT_CHUNK_OVERLAP=1200
#DSPYTEACH_LMSTUDIO_CONTEXT_LENGTH=131072
#DSPYTEACH_PROMPT_QUALITY_PROFILE=balanced
#DSPYTEACH_PROMPT_REDUCE_BATCH_SIZE=8
#DSPYTEACH_PROMPT_COVERAGE_CRITIC=false
#DSPYTEACH_PROMPT_EVIDENCE_CACHE_DIR=.dspyteach/cache/prompt_evidence
#DSPYTEACH_PROMPT_MAX_PARALLEL_CHUNKS=4
#DSPYTEACH_LMSTUDIO_TIMEOUT_SECONDS=60
```

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 general DSPy visible-output cap for non-prompt modes. It is not model context length
- `DSPYTEACH_LM_TEMPERATURE`, `DSPYTEACH_LM_TOP_P`, `DSPYTEACH_LM_TOP_K`, `DSPYTEACH_LM_MIN_P`, `DSPYTEACH_LM_REASONING`, `DSPYTEACH_LM_N_COMPLETIONS`, `DSPYTEACH_LM_MAX_TOKENS`, `DSPYTEACH_LM_STOP`, `DSPYTEACH_LM_PRESENCE_PENALTY`, `DSPYTEACH_LM_FREQUENCY_PENALTY`, and `DSPYTEACH_LM_REPEAT_PENALTY` are mode-agnostic LM request defaults used across teaching, prompt, refactor, and LM Studio request-body paths. `DSPYTEACH_LM_REASONING` accepts on/off-style values and maps to `enable_thinking`/`chat_template_kwargs.enable_thinking` for OpenAI-compatible local providers that support it. `DSPYTEACH_TEMPERATURE` and `DSPYTEACH_GLOBAL_TEMPERATURE` are compatibility aliases for temperature; prefer `DSPYTEACH_LM_TEMPERATURE` for new config
- `DSPYTEACH_PROMPT_MAX_TOKENS` controls the prompt-mode visible-output cap for direct prompt responses and evidence/reduce calls. It is not model context length; raise it only when clean outputs are truncated
- `DSPYTEACH_PROMPT_MIN_WORDS` optionally sets a prompt-mode coverage floor. When set above `0`, LM Studio prompt mode continues short-but-clean completions until the floor is met or the continuation budget is exhausted
- `DSPYTEACH_PROMPT_EVIDENCE_MIN_CHARS`, `DSPYTEACH_PROMPT_CHUNK_CHARS`, and `DSPYTEACH_PROMPT_CHUNK_OVERLAP` control the internal prompt-mode evidence pipeline. Large inputs are automatically chunked into evidence cards and reduced back to one final output; this is not a separate CLI mode
- `DSPYTEACH_LMSTUDIO_CONTEXT_LENGTH` optionally overrides detected LM Studio context-window length for the context-pressure selector. This is total input + output capacity, not an output cap. When unset, DSPyTeach attempts to read LM Studio model metadata and falls back to the character threshold if unavailable
- `DSPYTEACH_PROMPT_QUALITY_PROFILE` selects internal quality defaults; explicit env values still override profile-derived defaults:
  - `fast`: no prompt word floor, larger reduce batches, no coverage critic, no evidence cache
  - `balanced`: 2500-word prompt floor, medium reduce batches, no coverage critic, no evidence cache
  - `thorough`: 3500-word prompt floor, smaller reduce batches, coverage critic on, evidence cache enabled
  - `audit`: 4500-word prompt floor, smallest reduce batches, coverage critic on, evidence cache enabled
- `DSPYTEACH_PROMPT_REDUCE_BATCH_SIZE` controls hierarchical reduce batching for large evidence-card sets
- `DSPYTEACH_PROMPT_COVERAGE_CRITIC` enables an extra coverage critic and targeted expansion pass after final synthesis. It is temporarily validation-gated while runtime/evaluation evidence is collected, then should become automatic when it proves reliable
- `DSPYTEACH_PROMPT_EVIDENCE_CACHE_DIR` enables evidence-card caching for exact source/prompt/model/config matches. It is temporarily explicit to avoid uncontrolled cache growth until cache hygiene is validated
- `DSPYTEACH_PROMPT_MAX_PARALLEL_CHUNKS` enables bounded parallel chunk mapping. Default `4` aligns with LM Studio's documented default Max Concurrent Predictions for parallel requests; lower it if your local server or hardware becomes memory-bound
- `DSPYTEACH_LMSTUDIO_TIMEOUT_SECONDS` controls the LM Studio HTTP request timeout; set it to `0`, `off`, `none`, or `disabled` to remove the timeout entirely

See:

- `.env.example`
- `docs/guide/configuration.md`

---

## Usage

### Analyze a single file

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

### Analyze a directory recursively

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

### Write outputs to a separate mirrored tree

```bash
dspyteach analyze ./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 analyze ./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 analyze ./repo -g '**/*.md' --confirm-each
```

### Print raw predictions

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

### Run a history-first audit over mixed artifacts

```bash
dspyteach audit all ./history \
  --glob '**/*.json' \
  --glob '**/*.jsonl' \
  --glob '**/*.md' \
  --output-dir ./.dspyteach/audit/pilot \
  --run-id audit-pilot
```

After labeling, audit writes `repeated-query-patterns.json` and `audit-target-routes.jsonl` so repeated user-query patterns and follow-up destinations can feed governance, knowledge, correction-pattern, or workflow-handoff review.

### Create a TODO handoff list for agents

```bash
dspyteach todos scan ./repo --output todo-handoff.md
```

Use `--marker` to search for additional marker words, `--exclude-dir` to skip generated or vendor directories, and `--json` when another tool should consume the findings.

### General user workflow

The normal flow looks like this:

1. install the project
2. verify `dspyteach --help`
3. run `dspyteach analyze ...` on one file
4. run `dspyteach analyze ...` on a directory if needed
5. inspect or resume the analyze run
6. run `dspyteach audit all ...` on mixed history artifacts
7. resume the audit if needed
8. review the staged outputs

Smallest useful examples:

```bash
dspyteach analyze README.md
```

```bash
dspyteach audit all ./history --glob '**/*.md' --output-dir ./audit-out
```

More complete examples live in [`docs/guide/user-workflow.md`](docs/guide/user-workflow.md).

This staged workflow writes:

- `run-inventory.jsonl`
- `run-inventory.labeled.jsonl`
- `prompt-signatures.csv`
- `prompt-role-map.csv` (compatibility alias)
- `coverage-matrix.csv`
- `best-pairings.csv`
- `overlap-report.md`
- `missing-roles.md`
- `placement-recommendations.md`

Resume a prior audit run:

```bash
dspyteach audit all ./history \
  --glob '**/*.json' \
  --glob '**/*.jsonl' \
  --glob '**/*.md' \
  --output-dir ./.dspyteach/audit/pilot \
  --resume audit-pilot
```

For the command and artifact contract, see `docs/audit-cli-contract.md`.

## Documentation

Start with the docs index when you are not sure where to go next:

- [`docs/README.md`](docs/README.md) – documentation map for users and agents
- [`docs/guide/tui.md`](docs/guide/tui.md) – interactive Textual TUI guide
- [`docs/product/overview.md`](docs/product/overview.md) – product overview and core workflows
- [`docs/architecture/README.md`](docs/architecture/README.md) – architecture entry points and agent navigation rules
- [`docs/runbooks/local-dev.md`](docs/runbooks/local-dev.md) – local setup and validation commands
- [`docs/runbooks/deploy.md`](docs/runbooks/deploy.md) – release/deployment checklist
- [`docs/planning/roadmap.md`](docs/planning/roadmap.md) – human-readable roadmap and backlog
- [`docs/audit-source-contract.md`](docs/audit-source-contract.md) – canonical Audit Source and Run Evidence contract for history-first audits
- [`docs/audit-conversation-export-contract.md`](docs/audit-conversation-export-contract.md) – Conversation Export adapter guidance for Markdown conversation exports used by audit and Prompt Evidence Run provenance
- [`docs/audit-cli-contract.md`](docs/audit-cli-contract.md) – audit command surface, staged outputs, resume behavior, and extracted metadata
- [`docs/lm-studio-provider.md`](docs/lm-studio-provider.md) – LM Studio provider notes and troubleshooting
- [`docs/RELEASING.md`](docs/RELEASING.md) – release workflow

---

## Globs

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

Good:

```bash
dspyteach analyze ../../../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 analyze path/to/file.md --mode teach
```

Teach mode supports `-p/--prompt` for style, focus, and audience guidance while preserving the required overview, teaching-points, and report contracts:

```bash
dspyteach analyze path/to/file.md --mode teach --prompt prompts/teaching-style.md
```

When using LM Studio or another OpenAI-compatible provider, custom teaching prompts do not replace the structured JSON requirements for the overview and teaching-points stages; they are added as guidance inside the existing request messages.

### Refactor mode

Generates a refactor-oriented prompt template.

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

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

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

If multiple bundled templates are available and you run refactor mode without `--prompt`, the CLI will prompt you to choose one.

### Prompt mode

Runs a prompt directly against the file without applying teach or refactor structure. Prompt mode requires `--prompt`:

```bash
dspyteach analyze path/to/file.py --mode prompt --prompt prompts/security-review.md
```

The prompt is the primary instruction, and the file path/content are supplied as context. Prompt mode preserves the model output as text, including JSON-looking output if your prompt asks for JSON. Prompt mode output files use `.prompt.md` by default. For large inputs, Prompt Evidence Run uses the shared Conversation Export source contract to preserve `C#/M#` provenance when Markdown conversation exports are detected, and the Quality Contract enforces requested Source Map/citation shape when the prompt asks for it.

You can validate prompt-mode output locally against a JSON Schema file before anything is written:

```bash
dspyteach analyze path/to/file.py \
  --mode prompt \
  --prompt prompts/json-review.md \
  --prompt-output-schema schemas/review.schema.json
```

The schema check is post-generation validation: the provider is not forced to use a structured response format, and invalid JSON or schema mismatches fail the file before writing output.

You can override the generated filename suffix for any mode:

```bash
dspyteach analyze path/to/file.py \
  --mode prompt \
  --prompt prompts/json-review.md \
  --output-suffix .review.json
```

---

## Output behavior

Current behavior:

- if `--output-dir` is **omitted**, the CLI writes output under `.dspyteach/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`; prompt mode appends `.prompt.md`
- `--output-suffix` overrides the generated output suffix when not writing the original filename in place
- `--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 analyze ../../../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 analyze ./repo -g '**/*.py' --run-id docs-pass-1
```

Resume a saved run:

```bash
dspyteach analyze ./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 analyze --list-runs
```

Show one run and its per-file checkpoint stages:

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

Machine-readable output is also available:

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

### Delete or prune saved runs

Delete a single saved run:

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

Preview which runs would be pruned without deleting them:

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

Delete completed runs older than 14 days:

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

Preview prune results as JSON:

```bash
dspyteach analyze --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 analyze ./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 analyze ./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

Pre-push/global-hook friendly test entrypoint:

```bash
npm test
```

This runs governance validation plus the project Python checks. The project-only check is also available:

```bash
npm run test:project
```

Targeted Python 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/`
