otko/AGENTS.md
smillmorel 612936a00b
Some checks failed
CI / lint (push) Has been cancelled
CI / test (macos-latest, 3.10) (push) Has been cancelled
CI / test (macos-latest, 3.11) (push) Has been cancelled
CI / test (macos-latest, 3.12) (push) Has been cancelled
CI / test (ubuntu-latest, 3.10) (push) Has been cancelled
CI / test (ubuntu-latest, 3.11) (push) Has been cancelled
CI / test (ubuntu-latest, 3.12) (push) Has been cancelled
CI / test (windows-latest, 3.10) (push) Has been cancelled
CI / test (windows-latest, 3.11) (push) Has been cancelled
CI / test (windows-latest, 3.12) (push) Has been cancelled
feat: initial otko import
2026-09-08 02:12:15 -04:00

3.1 KiB
Raw Blame History

AGENTS.md — otko

Pre-alpha SAP2000-style desktop GUI for OpenSeesPy. Python 3.10+; Windows requires 3.12+ (openseespywin==3.8.0.0 has no 3.11 wheel). Solver pinned: openseespy==3.8.0.0.

Install

pip install -e ".[gui,dev]"  # desktop: Qt + PyVista + dev tools
pip install -e .              # headless: core + services only, no Qt (scripts, notebooks, web backends)
python -m otko                # launch GUI (src/otko/app.py:run)

scipy/pandas in [gui] extras are phantom deps (not imported as of 2026-06) — do not add imports expecting them.

Architecture (enforced in review — see PR template)

Strict one-way MVVM + services: views → viewmodels → services → core.

  • core/ (entities: project.py, geometry/, materials/, sections/, loads/, analysis/, catalog/): stdlib + numpy + pydantic only. No Qt, no openseespy. Period.
  • services/ (opensees_runner.py, persistence.py, results.py, ...): may use core + h5py + openseespy. No Qt.
  • views/: PySide6/pyvistaqt only. No direct import openseespy — go through a service.
  • viewmodels/ bridges core↔Qt (signals, QUndoStack); commands/ holds QUndoCommand subclasses.
  • Rules: public functions need type hints + docstring; new domain entities go through Pydantic validation; ops >50 ms run off the GUI thread (AnalysisWorker in QThread, cancel via isInterruptionRequested(), results cross threads as lightweight ResultsHandle to HDF5).

Runner emits OpenSeesPy commands in fixed order (docs/architecture.md): wipe → model → node → fix → material → section → geomTransf → element → timeSeries → pattern/load → recorder → system/numberer/... → analyze. Never reorder.

Verify (in this order)

ruff check src tests
ruff format src tests          # line-length 100, E501 ignored
mypy src/otko/core src/otko/services
pytest -m "not slow"           # CI gate: lint → this, on 3.10/3.11/3.12 × ubuntu/windows/macos

Focused runs: pytest tests/unit (pure logic, ms), pytest tests/gui -k <name> (pytest-qt, needs display), pytest tests/integration -k <name> (real OpenSeesPy runs). Single test: pytest tests/unit/test_project.py::test_name -q. Markers: gui, slow. Linux GUI tests need xvfb-run -a pytest ... plus system Qt libs (see ci.yml apt list).

Notes: tests/conftest.py auto-ops.wipe()s the OpenSees domain between tests (lazy import so core tests stay Qt/OpenSees-free). Coverage omits views/. Commit style: Conventional Commits (feat:, fix:, ...). pre-commit install runs ruff + mypy (mypy hook scoped to core|services|viewmodels).

Examples & persistence

  • examples/*.py are source of truth; examples/*.osmodel are generated artifacts (checked in). Never hand-edit .osmodel — change the script and regen: python examples/cantilever.py (each script saves, reloads, asserts clean round-trip).
  • Projects persist as single Pydantic-validated JSON .osmodel (diffable); analysis output goes to *.osresults.h5 (HDF5, one group per case).
  • Quick smoke: open examples/cantilever.osmodel → run Tip-Load → M3 peaks 50 kN·m at fixed end.