dspyteach – DSPy File Teaching Analyzer
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 ...)
- a teaching brief (
dspyteach audit ...for history-first prompt-library audits over mixed artifacts such as.md,.json, and.jsonl;audit allalso writes repeated-query pattern and target-route artifacts after labelingdspyteach 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-diris 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 testsdspy_file/cli/– grouped CLI parser, interaction, runner, and orchestration surfacedspy_file/analysis/– grouped teaching, refactor, direct-prompt, validation, signatures, output, file-helper compatibility exports, and the Scan Source Module for deterministic source evidence recordsdspy_file/infrastructure/– grouped logging, run-state, provider-runtime, and LM Studio transport surfacedspy_file/audit_cli.py– history-first audit command family and orchestrationdspy_file/history_audit/– extractor, labeler, aggregator, coverage, and report stagesdspy_file/file_analyzer.py– teaching pipeline and compatibility patch surface for testsdspy_file/prompts/– bundled prompt templates and prompt-loading helpersARCHITECTURE.md– high-level codemap and module boundaries
Requirements
- Python
>=3.10,<3.12(frompyproject.toml) - a supported model backend:
- Ollama
- LM Studio
- OpenAI-compatible API
uvrecommended 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_KEYfalls back toOPENAI_API_KEYwhenDSPYTEACH_PROVIDER=openaiDSPYTEACH_LOG_PATHcontrols the runtime log file destinationDSPYTEACH_MAX_TOKENScontrols the general DSPy visible-output cap for non-prompt modes. It is not model context lengthDSPYTEACH_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, andDSPYTEACH_LM_REPEAT_PENALTYare mode-agnostic LM request defaults used across teaching, prompt, refactor, and LM Studio request-body paths.DSPYTEACH_LM_REASONINGaccepts on/off-style values and maps toenable_thinking/chat_template_kwargs.enable_thinkingfor OpenAI-compatible local providers that support it.DSPYTEACH_TEMPERATUREandDSPYTEACH_GLOBAL_TEMPERATUREare compatibility aliases for temperature; preferDSPYTEACH_LM_TEMPERATUREfor new configDSPYTEACH_PROMPT_MAX_TOKENScontrols 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 truncatedDSPYTEACH_PROMPT_MIN_WORDSoptionally sets a prompt-mode coverage floor. When set above0, LM Studio prompt mode continues short-but-clean completions until the floor is met or the continuation budget is exhaustedDSPYTEACH_PROMPT_EVIDENCE_MIN_CHARS,DSPYTEACH_PROMPT_CHUNK_CHARS, andDSPYTEACH_PROMPT_CHUNK_OVERLAPcontrol 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 modeDSPYTEACH_LMSTUDIO_CONTEXT_LENGTHoptionally 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 unavailableDSPYTEACH_PROMPT_QUALITY_PROFILEselects internal quality defaults; explicit env values still override profile-derived defaults:fast: no prompt word floor, larger reduce batches, no coverage critic, no evidence cachebalanced: 2500-word prompt floor, medium reduce batches, no coverage critic, no evidence cachethorough: 3500-word prompt floor, smaller reduce batches, coverage critic on, evidence cache enabledaudit: 4500-word prompt floor, smallest reduce batches, coverage critic on, evidence cache enabled
DSPYTEACH_PROMPT_REDUCE_BATCH_SIZEcontrols hierarchical reduce batching for large evidence-card setsDSPYTEACH_PROMPT_COVERAGE_CRITICenables 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 reliableDSPYTEACH_PROMPT_EVIDENCE_CACHE_DIRenables evidence-card caching for exact source/prompt/model/config matches. It is temporarily explicit to avoid uncontrolled cache growth until cache hygiene is validatedDSPYTEACH_PROMPT_MAX_PARALLEL_CHUNKSenables bounded parallel chunk mapping. Default4aligns with LM Studio's documented default Max Concurrent Predictions for parallel requests; lower it if your local server or hardware becomes memory-boundDSPYTEACH_LMSTUDIO_TIMEOUT_SECONDScontrols the LM Studio HTTP request timeout; set it to0,off,none, ordisabledto remove the timeout entirely
See:
.env.exampledocs/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:
- install the project
- verify
dspyteach --help - run
dspyteach analyze ...on one file - run
dspyteach analyze ...on a directory if needed - inspect or resume the analyze run
- run
dspyteach audit all ...on mixed history artifacts - resume the audit if needed
- 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.jsonlrun-inventory.labeled.jsonlprompt-signatures.csvprompt-role-map.csv(compatibility alias)coverage-matrix.csvbest-pairings.csvoverlap-report.mdmissing-roles.mdplacement-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:
docs/README.md– documentation map for users and agentsdocs/guide/tui.md– interactive Textual TUI guidedocs/product/overview.md– product overview and core workflowsdocs/architecture/README.md– architecture entry points and agent navigation rulesdocs/runbooks/local-dev.md– local setup and validation commandsdocs/runbooks/deploy.md– release/deployment checklistdocs/planning/roadmap.md– human-readable roadmap and backlogdocs/audit-source-contract.md– canonical Audit Source and Run Evidence contract for history-first auditsdocs/audit-conversation-export-contract.md– Conversation Export adapter guidance for Markdown conversation exports used by audit and Prompt Evidence Run provenancedocs/audit-cli-contract.md– audit command surface, staged outputs, resume behavior, and extracted metadatadocs/lm-studio-provider.md– LM Studio provider notes and troubleshootingdocs/RELEASING.md– release workflow
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-diris omitted, the CLI writes output under.dspyteach/data/ - if
--output-diris 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-suffixoverrides the generated output suffix when not writing the original filename in place--in-placerequests source replacement, but real overwrites require per-file confirmation- if
--in-placeis 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.jsonwith 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-dirplus--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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dspyteach-0.2.1.tar.gz.
File metadata
- Download URL: dspyteach-0.2.1.tar.gz
- Upload date:
- Size: 217.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.3 {"installer":{"name":"uv","version":"0.11.3","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":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cf5ebd8d042994e614ab39ac588b19465ca8f041c66aac2016c415114a48c40c
|
|
| MD5 |
2caec4f8db11ca6be7a607f4f37faf9b
|
|
| BLAKE2b-256 |
ded7b026db20322eb4cedd0298978f783270936fe5dda20f529a3a2174a07683
|
File details
Details for the file dspyteach-0.2.1-py3-none-any.whl.
File metadata
- Download URL: dspyteach-0.2.1-py3-none-any.whl
- Upload date:
- Size: 225.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.3 {"installer":{"name":"uv","version":"0.11.3","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":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7d2a90a44ec74eb1b5db237c0152bb0617efbb9ead4f970f866f4f4ecc96043e
|
|
| MD5 |
239e25bf1fe619dad1afbf000948b76c
|
|
| BLAKE2b-256 |
30c496a40a8241e1a0e6bf1faacfdcf2682e683c7efadaa0074452a90bc9f067
|