Move guided-workflow prompts into prompts.py

The 7 narrative prompts (design_filter, debug_circuit, etc.) are pure Message
builders with no tool dependencies -- relocate them to prompts.py, registered
on the shared mcp instance. server.py: 1876 -> 1568 lines.
This commit is contained in:
Ryan Malloy 2026-06-21 20:52:24 -06:00
parent ca6e15e751
commit dfb94bfcb9
2 changed files with 310 additions and 309 deletions

309
src/mcltspice/prompts.py Normal file
View File

@ -0,0 +1,309 @@
"""Guided-workflow prompts. Each returns a Message list and registers on the
shared mcp instance. Pure narrative -- no tool calls.
"""
from fastmcp.prompts import Message
from ._app import mcp
@mcp.prompt()
def design_filter(
filter_type: str = "lowpass",
topology: str = "rc",
cutoff_freq: str = "1kHz",
) -> list:
"""Guide through designing and simulating a filter circuit.
Args:
filter_type: lowpass, highpass, bandpass, or notch
topology: rc (1st order), rlc (2nd order), or sallen-key (active)
cutoff_freq: Target cutoff frequency with units
"""
return [Message(role="user", content=f"""Design a {filter_type} filter with these requirements:
- Topology: {topology}
- Cutoff frequency: {cutoff_freq}
Workflow:
1. Use create_netlist to build the circuit
2. Add .ac analysis directive for frequency sweep
3. Add .meas directive for -3dB bandwidth
4. Simulate with simulate_netlist
5. Use measure_bandwidth to verify cutoff frequency
6. Use get_waveform to inspect the frequency response
7. Adjust component values with create_netlist if needed
Tips:
- For RC lowpass: f_c = 1/(2*pi*R*C)
- For 2nd order: Q controls peaking, Butterworth Q=0.707
- Use search_spice_models to find op-amp models for active filters
""")]
@mcp.prompt()
def analyze_power_supply(schematic_path: str = "") -> list:
"""Guide through analyzing a power supply circuit.
Args:
schematic_path: Path to the power supply schematic
"""
path_instruction = (
f"The schematic is at: {schematic_path}"
if schematic_path
else "First, identify or create the power supply schematic."
)
return [Message(role="user", content=f"""Analyze a power supply circuit for key performance metrics.
{path_instruction}
Workflow:
1. Use read_schematic to understand the circuit topology
2. Use run_drc to check for design issues
3. Simulate with .tran analysis (include load step if applicable)
4. Use analyze_waveform with these analyses:
- "peak_to_peak" on output for ripple measurement
- "settling_time" for transient response
- "fft" on output to identify noise frequencies
5. If AC analysis available, use measure_bandwidth for loop gain
Key metrics to extract:
- Output voltage regulation (DC accuracy)
- Ripple voltage (peak-to-peak on output)
- Load transient response (settling time after step)
- Efficiency (input power vs output power)
""")]
@mcp.prompt()
def debug_circuit(schematic_path: str = "") -> list:
"""Guide through debugging a circuit that isn't working.
Args:
schematic_path: Path to the problematic schematic
"""
path_instruction = (
f"The schematic is at: {schematic_path}"
if schematic_path
else "First, identify the schematic file."
)
return [Message(role="user", content=f"""Systematic approach to debugging a circuit.
{path_instruction}
Step 1 - Validate the schematic:
- Use run_drc to catch obvious issues (missing ground, floating nodes)
- Use read_schematic to review component values and connections
Step 2 - Check simulation setup:
- Verify simulation directives are correct
- Check that models/subcircuits are available (search_spice_models)
Step 3 - Run and analyze:
- Simulate the circuit
- Use get_waveform to inspect key node voltages
- Compare expected vs actual values at each stage
Step 4 - Isolate the problem:
- Use edit_component to simplify (replace active devices with ideal)
- Use diff_schematics to track what changes fixed the issue
- Re-simulate after each change
Common issues:
- Wrong node connections (check wire endpoints)
- Missing bias voltages or ground
- Component values off by orders of magnitude
- Wrong model (check with search_spice_models)
""")]
@mcp.prompt()
def optimize_design(
circuit_type: str = "filter",
target_spec: str = "1kHz bandwidth",
) -> list:
"""Guide through optimizing a circuit to meet target specifications.
Args:
circuit_type: Type of circuit (filter, amplifier, regulator, oscillator)
target_spec: Target specification to achieve
"""
return [Message(role="user", content=f"""Optimize a {circuit_type} circuit to achieve: {target_spec}
Workflow:
1. Start with a template: use list_templates to see available circuits
2. Create the initial circuit with create_from_template
3. Simulate and measure the current performance
4. Use optimize_circuit to automatically tune component values:
- Define target metrics (bandwidth, gain, settling time, etc.)
- Specify component ranges with preferred E-series values
- Let the optimizer iterate (typically 10-20 simulations)
5. Verify the optimized design with a full simulation
6. Run Monte Carlo (monte_carlo tool) to check yield with tolerances
Tips:
- Start with reasonable initial values from the template
- Use E24 or E96 series for resistors/capacitors
- For filters: target bandwidth_hz metric
- For amplifiers: target gain_db and phase_margin_deg
- For regulators: target settling_time and peak_to_peak (ripple)
""")]
@mcp.prompt()
def monte_carlo_analysis(
circuit_description: str = "RC filter",
n_runs: str = "100",
) -> list:
"""Guide through Monte Carlo tolerance analysis.
Args:
circuit_description: What circuit to analyze
n_runs: Number of Monte Carlo iterations
"""
return [Message(role="user", content=f"""Run Monte Carlo tolerance analysis on: {circuit_description}
Number of runs: {n_runs}
Workflow:
1. Create or identify the netlist for your circuit
2. Use monte_carlo tool with component tolerances:
- Resistors: typically 1% (0.01) or 5% (0.05)
- Capacitors: typically 10% (0.1) or 20% (0.2)
- Inductors: typically 10% (0.1)
3. For each completed run, extract key metrics:
- Use get_waveform on each raw file
- Use analyze_waveform for RMS, peak-to-peak, etc.
- Use measure_bandwidth for filter circuits
4. Compute statistics across all runs:
- Mean and standard deviation of each metric
- Min/max (worst case)
- Yield: what percentage meet spec?
Tips:
- Use list_simulation_runs to understand stepped data
- For stepped simulations, use get_waveform with run parameter
- Start with fewer runs (10-20) to verify setup, then scale up
- Set seed for reproducible results during development
- Typical component tolerances:
- Metal film resistors: 1%
- Ceramic capacitors: 10-20%
- Electrolytic capacitors: 20%
- Inductors: 10-20%
""")]
@mcp.prompt()
def circuit_from_scratch(
description: str = "audio amplifier",
) -> list:
"""Guide through creating a complete circuit from scratch.
Args:
description: What circuit to build
"""
return [Message(role="user", content=f"""Build a complete circuit from scratch: {description}
Approach 1 - Use a template (recommended for common circuits):
1. Use list_templates to see available circuit templates
2. Use create_from_template with custom parameters
3. Simulate with simulate_netlist
4. Analyze results with get_waveform and analyze_waveform
Approach 2 - Build from components:
1. Use create_netlist to define components and connections
2. Use search_spice_models to find transistor/diode models
3. Use search_spice_subcircuits to find op-amp/IC models
4. Add simulation directives (.tran, .ac, .dc, .op, .tf)
5. Simulate and analyze
Approach 3 - Graphical schematic (.asc file):
1. Use generate_schematic for any of 10 topologies: rc_lowpass,
voltage_divider, inverting_amp, non_inverting_amp, common_emitter_amp,
colpitts_oscillator, differential_amp, buck_converter, ldo_regulator,
h_bridge
2. The .asc file can be opened in LTspice GUI for editing
3. Simulate with the simulate tool
Verification workflow:
1. Run run_drc to check for design issues before simulating
2. Start with .op analysis to verify DC bias point
3. Run .tf analysis for gain and impedance
4. Run .ac analysis for frequency response
5. Run .tran analysis for time-domain behavior
6. Use diff_schematics to compare design iterations
""")]
@mcp.prompt()
def troubleshoot_simulation(
error_description: str = "",
schematic_path: str = "",
) -> list:
"""Systematic checklist for diagnosing simulation failures.
Args:
error_description: What went wrong (error message, unexpected results, etc.)
schematic_path: Path to the problematic schematic or netlist
"""
path_note = (
f"Schematic/netlist: {schematic_path}"
if schematic_path
else "First, identify the schematic or netlist file."
)
error_note = (
f"Reported issue: {error_description}"
if error_description
else "No specific error described -- run full diagnostic."
)
return [Message(role="user", content=f"""Troubleshoot a simulation that isn't working correctly.
{path_note}
{error_note}
Diagnostic checklist (work through in order):
1. **Design Rule Check**
- Run run_drc on the schematic
- Fix any: missing ground, floating nodes, duplicate names, missing sim directive
2. **Installation & Setup**
- Run check_installation to verify Wine + LTspice
- Check that required .lib files exist
3. **Model Availability**
- Use search_spice_models to verify all transistor/diode models exist
- Use search_spice_subcircuits to verify op-amp models
- Common issue: model name in schematic doesn't match library
4. **Simulation Directive**
- Use read_schematic to check the directive
- Verify analysis type matches what you want (.tran, .ac, .dc, .op, .tf)
- For .tran: is the stop time long enough?
- For .ac: are start/stop frequencies reasonable?
5. **Node Connections**
- Use read_schematic to list all components and nets
- Check for disconnected nodes (components not wired)
- Verify ground connections on all return paths
6. **Run & Inspect**
- Simulate the circuit
- Check the log file for convergence warnings
- Use get_waveform to inspect node voltages
- Compare expected vs actual at each circuit stage
7. **Simplify & Isolate**
- Use edit_component to replace active devices with ideal ones
- Remove non-essential subcircuits
- Test each stage independently
- Add .ic directives if oscillators won't start
Common failure modes:
- Convergence failure: reduce timestep, add initial conditions
- All zeros: check ground connections and source polarity
- Unexpected clipping: check supply voltages and headroom
- Oscillation in DC circuit: add small capacitors on feedback
- Model not found: verify .lib/.include paths
""")]

View File

@ -16,11 +16,10 @@ import tempfile
from pathlib import Path
import numpy as np
from fastmcp.prompts import Message
# Domain modules register their tools/resources/prompts on the shared mcp
# instance at import time. Imported for that side effect only.
from . import library_tools, resources, spicebook_tools # noqa: F401,E402
from . import library_tools, prompts, resources, spicebook_tools # noqa: F401,E402
from ._app import mcp
from .batch import (
run_monte_carlo,
@ -1555,313 +1554,6 @@ def list_templates() -> dict:
}
# ============================================================================
# PROMPTS
# ============================================================================
@mcp.prompt()
def design_filter(
filter_type: str = "lowpass",
topology: str = "rc",
cutoff_freq: str = "1kHz",
) -> list:
"""Guide through designing and simulating a filter circuit.
Args:
filter_type: lowpass, highpass, bandpass, or notch
topology: rc (1st order), rlc (2nd order), or sallen-key (active)
cutoff_freq: Target cutoff frequency with units
"""
return [Message(role="user", content=f"""Design a {filter_type} filter with these requirements:
- Topology: {topology}
- Cutoff frequency: {cutoff_freq}
Workflow:
1. Use create_netlist to build the circuit
2. Add .ac analysis directive for frequency sweep
3. Add .meas directive for -3dB bandwidth
4. Simulate with simulate_netlist
5. Use measure_bandwidth to verify cutoff frequency
6. Use get_waveform to inspect the frequency response
7. Adjust component values with create_netlist if needed
Tips:
- For RC lowpass: f_c = 1/(2*pi*R*C)
- For 2nd order: Q controls peaking, Butterworth Q=0.707
- Use search_spice_models to find op-amp models for active filters
""")]
@mcp.prompt()
def analyze_power_supply(schematic_path: str = "") -> list:
"""Guide through analyzing a power supply circuit.
Args:
schematic_path: Path to the power supply schematic
"""
path_instruction = (
f"The schematic is at: {schematic_path}"
if schematic_path
else "First, identify or create the power supply schematic."
)
return [Message(role="user", content=f"""Analyze a power supply circuit for key performance metrics.
{path_instruction}
Workflow:
1. Use read_schematic to understand the circuit topology
2. Use run_drc to check for design issues
3. Simulate with .tran analysis (include load step if applicable)
4. Use analyze_waveform with these analyses:
- "peak_to_peak" on output for ripple measurement
- "settling_time" for transient response
- "fft" on output to identify noise frequencies
5. If AC analysis available, use measure_bandwidth for loop gain
Key metrics to extract:
- Output voltage regulation (DC accuracy)
- Ripple voltage (peak-to-peak on output)
- Load transient response (settling time after step)
- Efficiency (input power vs output power)
""")]
@mcp.prompt()
def debug_circuit(schematic_path: str = "") -> list:
"""Guide through debugging a circuit that isn't working.
Args:
schematic_path: Path to the problematic schematic
"""
path_instruction = (
f"The schematic is at: {schematic_path}"
if schematic_path
else "First, identify the schematic file."
)
return [Message(role="user", content=f"""Systematic approach to debugging a circuit.
{path_instruction}
Step 1 - Validate the schematic:
- Use run_drc to catch obvious issues (missing ground, floating nodes)
- Use read_schematic to review component values and connections
Step 2 - Check simulation setup:
- Verify simulation directives are correct
- Check that models/subcircuits are available (search_spice_models)
Step 3 - Run and analyze:
- Simulate the circuit
- Use get_waveform to inspect key node voltages
- Compare expected vs actual values at each stage
Step 4 - Isolate the problem:
- Use edit_component to simplify (replace active devices with ideal)
- Use diff_schematics to track what changes fixed the issue
- Re-simulate after each change
Common issues:
- Wrong node connections (check wire endpoints)
- Missing bias voltages or ground
- Component values off by orders of magnitude
- Wrong model (check with search_spice_models)
""")]
@mcp.prompt()
def optimize_design(
circuit_type: str = "filter",
target_spec: str = "1kHz bandwidth",
) -> list:
"""Guide through optimizing a circuit to meet target specifications.
Args:
circuit_type: Type of circuit (filter, amplifier, regulator, oscillator)
target_spec: Target specification to achieve
"""
return [Message(role="user", content=f"""Optimize a {circuit_type} circuit to achieve: {target_spec}
Workflow:
1. Start with a template: use list_templates to see available circuits
2. Create the initial circuit with create_from_template
3. Simulate and measure the current performance
4. Use optimize_circuit to automatically tune component values:
- Define target metrics (bandwidth, gain, settling time, etc.)
- Specify component ranges with preferred E-series values
- Let the optimizer iterate (typically 10-20 simulations)
5. Verify the optimized design with a full simulation
6. Run Monte Carlo (monte_carlo tool) to check yield with tolerances
Tips:
- Start with reasonable initial values from the template
- Use E24 or E96 series for resistors/capacitors
- For filters: target bandwidth_hz metric
- For amplifiers: target gain_db and phase_margin_deg
- For regulators: target settling_time and peak_to_peak (ripple)
""")]
@mcp.prompt()
def monte_carlo_analysis(
circuit_description: str = "RC filter",
n_runs: str = "100",
) -> list:
"""Guide through Monte Carlo tolerance analysis.
Args:
circuit_description: What circuit to analyze
n_runs: Number of Monte Carlo iterations
"""
return [Message(role="user", content=f"""Run Monte Carlo tolerance analysis on: {circuit_description}
Number of runs: {n_runs}
Workflow:
1. Create or identify the netlist for your circuit
2. Use monte_carlo tool with component tolerances:
- Resistors: typically 1% (0.01) or 5% (0.05)
- Capacitors: typically 10% (0.1) or 20% (0.2)
- Inductors: typically 10% (0.1)
3. For each completed run, extract key metrics:
- Use get_waveform on each raw file
- Use analyze_waveform for RMS, peak-to-peak, etc.
- Use measure_bandwidth for filter circuits
4. Compute statistics across all runs:
- Mean and standard deviation of each metric
- Min/max (worst case)
- Yield: what percentage meet spec?
Tips:
- Use list_simulation_runs to understand stepped data
- For stepped simulations, use get_waveform with run parameter
- Start with fewer runs (10-20) to verify setup, then scale up
- Set seed for reproducible results during development
- Typical component tolerances:
- Metal film resistors: 1%
- Ceramic capacitors: 10-20%
- Electrolytic capacitors: 20%
- Inductors: 10-20%
""")]
@mcp.prompt()
def circuit_from_scratch(
description: str = "audio amplifier",
) -> list:
"""Guide through creating a complete circuit from scratch.
Args:
description: What circuit to build
"""
return [Message(role="user", content=f"""Build a complete circuit from scratch: {description}
Approach 1 - Use a template (recommended for common circuits):
1. Use list_templates to see available circuit templates
2. Use create_from_template with custom parameters
3. Simulate with simulate_netlist
4. Analyze results with get_waveform and analyze_waveform
Approach 2 - Build from components:
1. Use create_netlist to define components and connections
2. Use search_spice_models to find transistor/diode models
3. Use search_spice_subcircuits to find op-amp/IC models
4. Add simulation directives (.tran, .ac, .dc, .op, .tf)
5. Simulate and analyze
Approach 3 - Graphical schematic (.asc file):
1. Use generate_schematic for any of 10 topologies: rc_lowpass,
voltage_divider, inverting_amp, non_inverting_amp, common_emitter_amp,
colpitts_oscillator, differential_amp, buck_converter, ldo_regulator,
h_bridge
2. The .asc file can be opened in LTspice GUI for editing
3. Simulate with the simulate tool
Verification workflow:
1. Run run_drc to check for design issues before simulating
2. Start with .op analysis to verify DC bias point
3. Run .tf analysis for gain and impedance
4. Run .ac analysis for frequency response
5. Run .tran analysis for time-domain behavior
6. Use diff_schematics to compare design iterations
""")]
@mcp.prompt()
def troubleshoot_simulation(
error_description: str = "",
schematic_path: str = "",
) -> list:
"""Systematic checklist for diagnosing simulation failures.
Args:
error_description: What went wrong (error message, unexpected results, etc.)
schematic_path: Path to the problematic schematic or netlist
"""
path_note = (
f"Schematic/netlist: {schematic_path}"
if schematic_path
else "First, identify the schematic or netlist file."
)
error_note = (
f"Reported issue: {error_description}"
if error_description
else "No specific error described -- run full diagnostic."
)
return [Message(role="user", content=f"""Troubleshoot a simulation that isn't working correctly.
{path_note}
{error_note}
Diagnostic checklist (work through in order):
1. **Design Rule Check**
- Run run_drc on the schematic
- Fix any: missing ground, floating nodes, duplicate names, missing sim directive
2. **Installation & Setup**
- Run check_installation to verify Wine + LTspice
- Check that required .lib files exist
3. **Model Availability**
- Use search_spice_models to verify all transistor/diode models exist
- Use search_spice_subcircuits to verify op-amp models
- Common issue: model name in schematic doesn't match library
4. **Simulation Directive**
- Use read_schematic to check the directive
- Verify analysis type matches what you want (.tran, .ac, .dc, .op, .tf)
- For .tran: is the stop time long enough?
- For .ac: are start/stop frequencies reasonable?
5. **Node Connections**
- Use read_schematic to list all components and nets
- Check for disconnected nodes (components not wired)
- Verify ground connections on all return paths
6. **Run & Inspect**
- Simulate the circuit
- Check the log file for convergence warnings
- Use get_waveform to inspect node voltages
- Compare expected vs actual at each circuit stage
7. **Simplify & Isolate**
- Use edit_component to replace active devices with ideal ones
- Remove non-essential subcircuits
- Test each stage independently
- Add .ic directives if oscillators won't start
Common failure modes:
- Convergence failure: reduce timestep, add initial conditions
- All zeros: check ground connections and source polarity
- Unexpected clipping: check supply voltages and headroom
- Oscillation in DC circuit: add small capacitors on feedback
- Model not found: verify .lib/.include paths
""")]
# ============================================================================
# ENTRY POINT
# ============================================================================