- ✅ Python Subprocess Approach: Working reliably
- ✅ Library Analysis:
fusionscript.soanalyzed and accessible - ✅ Performance Baseline: ~307ms per API call via subprocess
- ❓ Native Integration: Possible but complex
- Average call time: 306ms
- Overhead: Python process startup, JSON serialization
- Reliability: High (isolated processes)
- Memory usage: Low (processes cleaned up)
- Estimated call time: ~1ms (306x faster)
- Overhead: Python C API calls only
- Reliability: Medium (shared memory space)
- Memory usage: Higher (persistent Python objects)
# Add to Cargo.toml
[dependencies]
pyo3 = { version = "0.20", features = ["auto-initialize"] }Goals:
- Add
pyo3dependency - Create basic Python interpreter embedding
- Load
fusionscriptmodule successfully - Call
scriptapp()function from Rust
Key challenges:
- Python GIL management
- Module path configuration
- Error handling between Rust and Python
Goals:
- Implement
Resolveobject wrapper - Create
ProjectManagerinterface - Add basic timeline operations
- Handle Python exceptions in Rust
Architecture:
pub struct NativeResolve {
py: Python<'_>,
resolve_obj: PyObject,
project_manager: Option<PyObject>,
}
impl NativeResolve {
pub fn new() -> PyResult<Self> {
Python::with_gil(|py| {
let fusionscript = py.import("fusionscript")?;
let resolve_obj = fusionscript.call_method1("scriptapp", ("Resolve",))?;
Ok(Self {
py,
resolve_obj: resolve_obj.to_object(py),
project_manager: None,
})
})
}
pub fn switch_page(&self, page: &str) -> PyResult<bool> {
Python::with_gil(|py| {
let result = self.resolve_obj
.call_method1(py, "OpenPage", (page,))?;
result.extract(py)
})
}
}Goals:
- Color grading operations
- Timeline item manipulation
- Keyframe animation
- Render queue management
Performance optimizations:
- Object caching
- Batch operations
- Async Python calls
Goals:
- Thread safety
- Memory leak prevention
- Error recovery
- Performance monitoring
- Fallback to subprocess on errors
Instead of full native replacement, implement selective native acceleration:
pub enum ApiCallStrategy {
Subprocess, // For complex/rare operations
Native, // For simple/frequent operations
Cached, // For repeated queries
}
impl ResolveBridge {
fn choose_strategy(&self, method: &str) -> ApiCallStrategy {
match method {
// Frequent operations -> Native
"switch_page" | "get_current_timeline" => ApiCallStrategy::Native,
// Complex operations -> Subprocess
"create_empty_timeline" | "add_to_render_queue" => ApiCallStrategy::Subprocess,
// Cacheable queries -> Cached
"list_timelines_tool" | "get_project_settings" => ApiCallStrategy::Cached,
_ => ApiCallStrategy::Subprocess,
}
}
}- Memory leaks from Python object references
- Segmentation faults from incorrect Python C API usage
- GIL deadlocks in multi-threaded scenarios
- Version compatibility issues with Python/DaVinci Resolve updates
- Performance regression if native calls are slower than expected
- Debugging complexity with mixed Rust/Python stack traces
- Maintenance overhead for two different API approaches
- Feature parity - Python subprocess approach as fallback
- Testing complexity - existing test suite covers functionality
Implement native integration IF:
- Performance becomes a bottleneck (>1000 API calls/minute)
- Real-time operations are required (live editing)
- Memory usage needs to be minimized
- Team has Python C API expertise
Stay with subprocess approach IF:
- Current performance is acceptable
- Reliability is more important than speed
- Development resources are limited
- Maintenance simplicity is preferred
Continue with Python subprocess approach because:
- ✅ Proven reliability - works consistently
- ✅ Simple maintenance - easy to debug and modify
- ✅ Adequate performance - 300ms is acceptable for MCP server
- ✅ Risk mitigation - isolated processes prevent crashes
- ✅ Development speed - focus on features, not optimization
Consider native integration later when:
- Performance requirements increase significantly
- Real-time features are needed
- Team gains Python C API expertise
- Stable foundation is established