| name | symusic-code-style |
| description | Encodes symusic's engineering taste across C++ core, nanobind bindings, and Python-facing APIs. Use when implementing or reviewing features to preserve performance-first architecture and ergonomic, predictable interfaces. |
| metadata | {"domain":"symusic","role":"project-specific-style-guide","scope":"implementation-and-review","output-format":"checklist-and-rationale"} |
Symusic Code Style and Engineering Taste
Use this skill whenever a change touches src/, include/, py_src/, python/symusic/, or tests/.
First-Principles Guidance
-
Performance is a product feature, not an optimization pass.
- Keep hot paths in C++ (
src/, include/) and expose them through thin nanobind layers.
- Prefer data representations that avoid repeated conversion and minimize allocation churn.
-
API symmetry beats cleverness.
- For transformations, preserve the
foo() + foo_inplace() dual interface.
- Preserve consistent behavior across time units (
Tick, Quarter, Second) and container types (Note, Track, Score).
-
Type-level correctness should be explicit at boundaries.
- Keep time-unit semantics explicit and dispatch through well-defined factories instead of ad-hoc runtime checks.
- Ensure Python-visible typing helpers remain informative and fail loudly on invalid construction.
-
Cross-language predictability is mandatory.
- Python APIs should feel ergonomic, but never hide semantic differences from the C++ core.
- Prefer deterministic behavior and clear exceptions over silent coercion.
-
Readable systems code over minimalist one-liners.
- Favor named helper functions and local structs when they clarify non-trivial timeline/algorithm logic.
- Document subtle invariants (time tolerance, ownership expectations, conversion assumptions) near the implementation.
Repository-Specific Style Patterns
C++ Core (include/, src/)
- Target modern C++ with explicit compile settings (
C++20, no compiler extensions).
- Use project aliases and containers (
i32, vec, shared, pyvec) consistently instead of mixing raw STL usage styles.
- Prefer value-semantic operations (
copy, deepcopy, non-inplace transforms) and keep deep-copy semantics explicit.
- Keep equality and ordering logic structural and deterministic, including pointer-aware equality fallbacks where needed.
- For numeric timeline logic:
- centralize tolerances,
- avoid duplicated floating-point comparisons,
- isolate helper predicates (
close_enough, ge_or_close) and step derivation logic.
Nanobind Layer (py_src/bindings/)
- Keep module entry points compact and delegate registrations to smaller binding units.
- Prefer explicit, user-facing error messages when classes are typing placeholders or generic helpers.
- Ensure pickle/state methods and reprs are predictable and stable.
- Guard optional diagnostics (
MEM_LEAK_WARNING) behind build flags rather than ad-hoc runtime branches.
Python API Layer (python/symusic/)
- Use factories to centralize dispatch across time units and core class variants.
- Keep constructors and conversion helpers straightforward; avoid hidden expensive operations.
- Raise precise exceptions (
TypeError for wrong object kind, ValueError for invalid value domain).
- Keep module import side-effects intentional, short, and validated (e.g., binary path checks).
Testing and Quality Signals (tests/ + pyproject.toml)
- Keep tests behavior-focused, with clear assertions for immutability contracts and I/O round-trips.
- Treat warnings as quality regressions where configured.
- Respect existing lint philosophy: broad Ruff coverage, targeted per-file exceptions, strict pytest options.
Change Checklist Before Merge
- Did the change preserve
inplace and non-inplace API symmetry where relevant?
- Are time-unit semantics (
tick/quarter/second) consistent and explicitly handled?
- Are exceptions and error messages concrete and user-actionable?
- Did you avoid adding hidden work in Python wrappers that belongs in C++?
- Are tests updated for behavior and edge cases, not just happy paths?
- Are comments/docstrings in English and focused on invariants rather than restating code?
Anti-Patterns to Avoid
- Introducing convenience wrappers that blur time-unit semantics.
- Adding dependencies to solve narrowly scoped problems already covered by existing internal utilities.
- Mixing ownership styles unpredictably (raw pointers vs shared/value semantics) in core data models.
- Creating Python-side fallback implementations for logic that should remain canonical in C++.