Skip to main content

dspyteach – DSPy File Teaching Analyzer


PyPI Downloads TestPyPI Release Repo


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

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

From PyPI

pip install dspyteach

Smoke checks:

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.

dspyteach analyze path/to/file.md

The current default Ollama base URL is:

http://localhost:11434

LM Studio

LM Studio uses the OpenAI-compatible server at:

http://localhost:1234/v1

Example:

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

More details:

Hosted OpenAI-compatible provider

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:

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

dspyteach analyze docs/example.md

Analyze a directory recursively

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

Write outputs to a separate mirrored tree

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

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

dspyteach analyze ./repo -g '**/*.md' --confirm-each

Print raw predictions

dspyteach analyze docs/example.md --raw

Run a history-first audit over mixed artifacts

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

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:

dspyteach analyze README.md
dspyteach audit all ./history --glob '**/*.md' --output-dir ./audit-out

More complete examples live in 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:

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:


Globs

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

Good:

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

Not recommended:

# 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.

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:

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.

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

Refactor mode also supports -p/--prompt:

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:

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:

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:

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:

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:

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

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

Override it with:

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:

.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:

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

Resume a saved run:

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:

dspyteach analyze --list-runs

Show one run and its per-file checkpoint stages:

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

Machine-readable output is also available:

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

Delete or prune saved runs

Delete a single saved run:

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

Preview which runs would be pruned without deleting them:

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

Delete completed runs older than 14 days:

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

Preview prune results as JSON:

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

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

Releasing

Maintainer release steps live in:

Tag workflow helper:

./scripts/tag-release.sh

Pushing a tag matching v* triggers:

  • .github/workflows/release.yml

Development notes

Pre-push/global-hook friendly test entrypoint:

npm test

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

npm run test:project

Targeted Python test runs used frequently in this repo:

uv run pytest -q

Focused examples:

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/

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dspyteach-0.1.8.tar.gz (220.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dspyteach-0.1.8-py3-none-any.whl (223.0 kB view details)

Uploaded Python 3

File details

Details for the file dspyteach-0.1.8.tar.gz.

File metadata

  • Download URL: dspyteach-0.1.8.tar.gz
  • Upload date:
  • Size: 220.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for dspyteach-0.1.8.tar.gz
Algorithm Hash digest
SHA256 a9cccedfc3322a9b811ec41c13592d177277daa066c54e57ff205080b17ebe4d
MD5 bdaf6a25a9737bfc763ce580760d0edf
BLAKE2b-256 36c7a248c686025d9053f0ca1ce28f5dd59a72852bbd5442ee41db8936e310da

See more details on using hashes here.

File details

Details for the file dspyteach-0.1.8-py3-none-any.whl.

File metadata

  • Download URL: dspyteach-0.1.8-py3-none-any.whl
  • Upload date:
  • Size: 223.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for dspyteach-0.1.8-py3-none-any.whl
Algorithm Hash digest
SHA256 b7a4e52f3e304e4880e7376fb96322cd72ede9e24b4d456bf851a92e30d8a756
MD5 df05f7530891b793b0426a7cfcd20dc3
BLAKE2b-256 d1a3499a27edf4753146303b240d049e4770f1ace1aed11e9913c74d1f9303d7

See more details on using hashes here.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page