mycorrhizal 0.1.2__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mycorrhizal-0.2.0/.github/workflows/test.yml +42 -0
- mycorrhizal-0.2.0/.gitignore +67 -0
- mycorrhizal-0.2.0/.readthedocs.yaml +21 -0
- mycorrhizal-0.2.0/PKG-INFO +335 -0
- mycorrhizal-0.2.0/README.md +318 -0
- mycorrhizal-0.2.0/docs/api/common.md +33 -0
- mycorrhizal-0.2.0/docs/api/hypha.md +38 -0
- mycorrhizal-0.2.0/docs/api/index.md +11 -0
- mycorrhizal-0.2.0/docs/api/rhizomorph.md +18 -0
- mycorrhizal-0.2.0/docs/api/septum.md +11 -0
- mycorrhizal-0.2.0/docs/api/spores.md +37 -0
- mycorrhizal-0.2.0/docs/assets/stylesheets/extra.css +3 -0
- mycorrhizal-0.2.0/docs/getting-started/index.md +20 -0
- mycorrhizal-0.2.0/docs/getting-started/installation.md +59 -0
- mycorrhizal-0.2.0/docs/getting-started/your-first-hypha.md +156 -0
- mycorrhizal-0.2.0/docs/getting-started/your-first-mycelium.md +424 -0
- mycorrhizal-0.2.0/docs/getting-started/your-first-rhizomorph.md +193 -0
- mycorrhizal-0.2.0/docs/getting-started/your-first-septum.md +155 -0
- mycorrhizal-0.2.0/docs/getting-started/your-first-spores.md +218 -0
- mycorrhizal-0.2.0/docs/guides/best-practices.md +480 -0
- mycorrhizal-0.2.0/docs/guides/blackboards.md +520 -0
- mycorrhizal-0.2.0/docs/guides/composition.md +367 -0
- mycorrhizal-0.2.0/docs/guides/index.md +20 -0
- mycorrhizal-0.2.0/docs/guides/observability.md +252 -0
- mycorrhizal-0.2.0/docs/guides/programmatic-hypha.md +571 -0
- mycorrhizal-0.2.0/docs/guides/septum-pda-guide.md +960 -0
- mycorrhizal-0.2.0/docs/guides/timebases.md +256 -0
- mycorrhizal-0.2.0/docs/hypha/index.md +352 -0
- mycorrhizal-0.2.0/docs/index.md +356 -0
- mycorrhizal-0.2.0/docs/mycelium/index.md +254 -0
- mycorrhizal-0.2.0/docs/rhizomorph/index.md +355 -0
- mycorrhizal-0.2.0/docs/septum/index.md +228 -0
- mycorrhizal-0.2.0/docs/septum/production.md +656 -0
- mycorrhizal-0.2.0/docs/septum/troubleshooting.md +720 -0
- mycorrhizal-0.2.0/docs/spores/index.md +332 -0
- mycorrhizal-0.2.0/mkdocs.yml +169 -0
- {mycorrhizal-0.1.2 → mycorrhizal-0.2.0}/pyproject.toml +49 -1
- mycorrhizal-0.2.0/src/mycorrhizal/_version.py +1 -0
- {mycorrhizal-0.1.2 → mycorrhizal-0.2.0}/src/mycorrhizal/common/__init__.py +15 -3
- mycorrhizal-0.2.0/src/mycorrhizal/common/cache.py +114 -0
- mycorrhizal-0.2.0/src/mycorrhizal/common/compilation.py +263 -0
- mycorrhizal-0.2.0/src/mycorrhizal/common/interface_detection.py +159 -0
- {mycorrhizal-0.1.2 → mycorrhizal-0.2.0}/src/mycorrhizal/common/interfaces.py +3 -50
- mycorrhizal-0.2.0/src/mycorrhizal/common/mermaid.py +124 -0
- {mycorrhizal-0.1.2 → mycorrhizal-0.2.0}/src/mycorrhizal/common/wrappers.py +1 -1
- {mycorrhizal-0.1.2 → mycorrhizal-0.2.0}/src/mycorrhizal/hypha/core/builder.py +11 -1
- {mycorrhizal-0.1.2 → mycorrhizal-0.2.0}/src/mycorrhizal/hypha/core/runtime.py +242 -107
- mycorrhizal-0.2.0/src/mycorrhizal/mycelium/__init__.py +174 -0
- mycorrhizal-0.2.0/src/mycorrhizal/mycelium/core.py +619 -0
- mycorrhizal-0.2.0/src/mycorrhizal/mycelium/exceptions.py +30 -0
- mycorrhizal-0.2.0/src/mycorrhizal/mycelium/hypha_bridge.py +1143 -0
- mycorrhizal-0.2.0/src/mycorrhizal/mycelium/instance.py +440 -0
- mycorrhizal-0.2.0/src/mycorrhizal/mycelium/pn_context.py +276 -0
- mycorrhizal-0.2.0/src/mycorrhizal/mycelium/runner.py +165 -0
- mycorrhizal-0.2.0/src/mycorrhizal/mycelium/spores_integration.py +655 -0
- mycorrhizal-0.2.0/src/mycorrhizal/mycelium/tree_builder.py +102 -0
- mycorrhizal-0.2.0/src/mycorrhizal/mycelium/tree_spec.py +197 -0
- {mycorrhizal-0.1.2 → mycorrhizal-0.2.0}/src/mycorrhizal/rhizomorph/README.md +82 -33
- {mycorrhizal-0.1.2 → mycorrhizal-0.2.0}/src/mycorrhizal/rhizomorph/core.py +287 -119
- mycorrhizal-0.2.0/src/mycorrhizal/septum/TRANSITION_REFERENCE.md +385 -0
- {mycorrhizal-0.1.2/src/mycorrhizal/enoki → mycorrhizal-0.2.0/src/mycorrhizal/septum}/core.py +326 -100
- {mycorrhizal-0.1.2/src/mycorrhizal/enoki → mycorrhizal-0.2.0/src/mycorrhizal/septum}/testing_utils.py +7 -7
- {mycorrhizal-0.1.2/src/mycorrhizal/enoki → mycorrhizal-0.2.0/src/mycorrhizal/septum}/util.py +44 -21
- {mycorrhizal-0.1.2 → mycorrhizal-0.2.0}/src/mycorrhizal/spores/__init__.py +3 -3
- {mycorrhizal-0.1.2 → mycorrhizal-0.2.0}/src/mycorrhizal/spores/core.py +149 -28
- {mycorrhizal-0.1.2 → mycorrhizal-0.2.0}/src/mycorrhizal/spores/dsl/__init__.py +8 -8
- {mycorrhizal-0.1.2 → mycorrhizal-0.2.0}/src/mycorrhizal/spores/dsl/hypha.py +3 -15
- {mycorrhizal-0.1.2 → mycorrhizal-0.2.0}/src/mycorrhizal/spores/dsl/rhizomorph.py +3 -11
- mycorrhizal-0.1.2/src/mycorrhizal/spores/dsl/enoki.py → mycorrhizal-0.2.0/src/mycorrhizal/spores/dsl/septum.py +26 -77
- {mycorrhizal-0.1.2 → mycorrhizal-0.2.0}/src/mycorrhizal/spores/encoder/json.py +21 -12
- {mycorrhizal-0.1.2 → mycorrhizal-0.2.0}/src/mycorrhizal/spores/extraction.py +14 -11
- {mycorrhizal-0.1.2 → mycorrhizal-0.2.0}/src/mycorrhizal/spores/models.py +53 -20
- mycorrhizal-0.2.0/uv.lock +1704 -0
- mycorrhizal-0.1.2/.gitignore +0 -7
- mycorrhizal-0.1.2/PKG-INFO +0 -198
- mycorrhizal-0.1.2/README.md +0 -188
- mycorrhizal-0.1.2/src/mycorrhizal/_version.py +0 -1
- mycorrhizal-0.1.2/uv.lock +0 -477
- {mycorrhizal-0.1.2 → mycorrhizal-0.2.0}/.github/workflows/python-publish.yml +0 -0
- {mycorrhizal-0.1.2 → mycorrhizal-0.2.0}/src/mycorrhizal/__init__.py +0 -0
- {mycorrhizal-0.1.2 → mycorrhizal-0.2.0}/src/mycorrhizal/common/interface_builder.py +0 -0
- {mycorrhizal-0.1.2 → mycorrhizal-0.2.0}/src/mycorrhizal/common/timebase.py +0 -0
- {mycorrhizal-0.1.2/src/mycorrhizal/enoki → mycorrhizal-0.2.0/src/mycorrhizal/hypha}/__init__.py +0 -0
- {mycorrhizal-0.1.2 → mycorrhizal-0.2.0}/src/mycorrhizal/hypha/core/__init__.py +0 -0
- {mycorrhizal-0.1.2 → mycorrhizal-0.2.0}/src/mycorrhizal/hypha/core/specs.py +0 -0
- {mycorrhizal-0.1.2 → mycorrhizal-0.2.0}/src/mycorrhizal/hypha/util.py +0 -0
- {mycorrhizal-0.1.2/src/mycorrhizal/hypha → mycorrhizal-0.2.0/src/mycorrhizal/rhizomorph}/__init__.py +0 -0
- {mycorrhizal-0.1.2 → mycorrhizal-0.2.0}/src/mycorrhizal/rhizomorph/util.py +0 -0
- {mycorrhizal-0.1.2/src/mycorrhizal/rhizomorph → mycorrhizal-0.2.0/src/mycorrhizal/septum}/__init__.py +0 -0
- {mycorrhizal-0.1.2 → mycorrhizal-0.2.0}/src/mycorrhizal/spores/cache.py +0 -0
- {mycorrhizal-0.1.2 → mycorrhizal-0.2.0}/src/mycorrhizal/spores/encoder/__init__.py +0 -0
- {mycorrhizal-0.1.2 → mycorrhizal-0.2.0}/src/mycorrhizal/spores/encoder/base.py +0 -0
- {mycorrhizal-0.1.2 → mycorrhizal-0.2.0}/src/mycorrhizal/spores/transport/__init__.py +0 -0
- {mycorrhizal-0.1.2 → mycorrhizal-0.2.0}/src/mycorrhizal/spores/transport/base.py +0 -0
- {mycorrhizal-0.1.2 → mycorrhizal-0.2.0}/src/mycorrhizal/spores/transport/file.py +0 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ main, master ]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ main, master ]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
20
|
+
uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: ${{ matrix.python-version }}
|
|
23
|
+
|
|
24
|
+
- name: Install uv
|
|
25
|
+
run: pip install uv
|
|
26
|
+
|
|
27
|
+
- name: Setup virtual environment
|
|
28
|
+
run: uv venv
|
|
29
|
+
|
|
30
|
+
- name: Install dependencies
|
|
31
|
+
run: |
|
|
32
|
+
uv pip install -e ".[dev]"
|
|
33
|
+
|
|
34
|
+
- name: Run tests with coverage
|
|
35
|
+
run: |
|
|
36
|
+
uv run pytest --cov=src/mycorrhizal --cov-report=xml --cov-report=term
|
|
37
|
+
|
|
38
|
+
- name: Upload coverage to Codecov
|
|
39
|
+
uses: codecov/codecov-action@v4
|
|
40
|
+
with:
|
|
41
|
+
file: ./coverage.xml
|
|
42
|
+
fail_ci_if_error: false
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
|
|
2
|
+
**/__pycache__/
|
|
3
|
+
*.claude_todo/
|
|
4
|
+
*.pyclogs/
|
|
5
|
+
|
|
6
|
+
# Generated version file
|
|
7
|
+
src/*/_version.py
|
|
8
|
+
|
|
9
|
+
# Python
|
|
10
|
+
*.py[cod]
|
|
11
|
+
*$py.class
|
|
12
|
+
*.so
|
|
13
|
+
.Python
|
|
14
|
+
build/
|
|
15
|
+
develop-eggs/
|
|
16
|
+
dist/
|
|
17
|
+
downloads/
|
|
18
|
+
eggs/
|
|
19
|
+
.eggs/
|
|
20
|
+
lib/
|
|
21
|
+
lib64/
|
|
22
|
+
parts/
|
|
23
|
+
sdist/
|
|
24
|
+
var/
|
|
25
|
+
wheels/
|
|
26
|
+
pip-wheel-metadata/
|
|
27
|
+
share/python-wheels/
|
|
28
|
+
*.egg-info/
|
|
29
|
+
.installed.cfg
|
|
30
|
+
*.egg
|
|
31
|
+
MANIFEST
|
|
32
|
+
|
|
33
|
+
# Virtual environments
|
|
34
|
+
venv/
|
|
35
|
+
env/
|
|
36
|
+
ENV/
|
|
37
|
+
.venv
|
|
38
|
+
|
|
39
|
+
# Testing
|
|
40
|
+
.pytest_cache/
|
|
41
|
+
.coverage
|
|
42
|
+
.coverage.*
|
|
43
|
+
htmlcov/
|
|
44
|
+
.tox/
|
|
45
|
+
.nox/
|
|
46
|
+
.hypothesis/No
|
|
47
|
+
.hypothesis/
|
|
48
|
+
|
|
49
|
+
# Documentation builds
|
|
50
|
+
site/
|
|
51
|
+
.sphinx/
|
|
52
|
+
|
|
53
|
+
# IDEs
|
|
54
|
+
.vscode/
|
|
55
|
+
.idea/
|
|
56
|
+
*.swp
|
|
57
|
+
*.swo
|
|
58
|
+
*~
|
|
59
|
+
|
|
60
|
+
# OS
|
|
61
|
+
.DS_Store
|
|
62
|
+
Thumbs.db
|
|
63
|
+
|
|
64
|
+
# Project-specific
|
|
65
|
+
.claude_work/
|
|
66
|
+
logs/
|
|
67
|
+
*.log
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
|
|
3
|
+
build:
|
|
4
|
+
os: ubuntu-22.04
|
|
5
|
+
tools:
|
|
6
|
+
python: "3.10"
|
|
7
|
+
jobs:
|
|
8
|
+
post_create_environment:
|
|
9
|
+
- pip install uv
|
|
10
|
+
post_install:
|
|
11
|
+
- uv pip install -e ".[docs]"
|
|
12
|
+
|
|
13
|
+
python:
|
|
14
|
+
install:
|
|
15
|
+
- method: pip
|
|
16
|
+
path: .
|
|
17
|
+
|
|
18
|
+
# MkDocs configuration
|
|
19
|
+
mkdocs:
|
|
20
|
+
configuration: mkdocs.yml
|
|
21
|
+
fail_on_warning: false
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mycorrhizal
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Utilities and DSLs for modelling and implementing safe, performant, structured systems
|
|
5
|
+
Author-email: Jeff Ciesielski <jeffciesielski@gmail.com>
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Requires-Dist: pydantic>=2.11.7
|
|
8
|
+
Requires-Dist: typeguard==4.4.4
|
|
9
|
+
Provides-Extra: docs
|
|
10
|
+
Requires-Dist: mkdocs-literate-nav>=0.6.0; extra == 'docs'
|
|
11
|
+
Requires-Dist: mkdocs-material>=9.5.0; extra == 'docs'
|
|
12
|
+
Requires-Dist: mkdocs-section-index>=0.3.0; extra == 'docs'
|
|
13
|
+
Requires-Dist: mkdocs-table-reader-plugin>=2.0.0; extra == 'docs'
|
|
14
|
+
Requires-Dist: mkdocs>=1.6.0; extra == 'docs'
|
|
15
|
+
Requires-Dist: mkdocstrings[python]>=0.25.0; extra == 'docs'
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# Mycorrhizal
|
|
19
|
+
|
|
20
|
+
[](https://github.com/Jeff-Ciesielski/mycorrhizal/actions/workflows/test.yml)
|
|
21
|
+
[](https://codecov.io/gh/Jeff-Ciesielski/mycorrhizal)
|
|
22
|
+
[](https://mycorrhizal.readthedocs.io/en/latest/?badge=latest)
|
|
23
|
+
[](https://pypi.org/project/mycorrhizal/)
|
|
24
|
+
[](https://opensource.org/licenses/MIT)
|
|
25
|
+
|
|
26
|
+
A Python library for building safe, structured, concurrent, event-driven systems.
|
|
27
|
+
|
|
28
|
+
## Overview
|
|
29
|
+
|
|
30
|
+
Mycorrhizal provides four domain-specific languages (DSLs) for modeling and implementing different aspects of complex systems:
|
|
31
|
+
|
|
32
|
+
* **Hypha** - Colored Petri nets for workflow modeling and orchestration
|
|
33
|
+
* **Rhizomorph** - Behavior trees for decision-making and control logic
|
|
34
|
+
* **Septum** - Finite state machines for stateful components
|
|
35
|
+
* **Spores** - Event and object logging for observability and process mining
|
|
36
|
+
|
|
37
|
+
Each DSL can be used independently or combined to build sophisticated systems. All modules share common infrastructure for state management (blackboards) and time abstraction, enabling seamless composition.
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install mycorrhizal
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Requires Python 3.10 or later.
|
|
46
|
+
|
|
47
|
+
## Quick Start
|
|
48
|
+
|
|
49
|
+
### Behavior Tree (Rhizomorph)
|
|
50
|
+
|
|
51
|
+
Define behavior trees using a decorator-based DSL:
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from mycorrhizal.rhizomorph.core import bt, Runner, Status
|
|
55
|
+
|
|
56
|
+
@bt.tree
|
|
57
|
+
def ThreatResponse():
|
|
58
|
+
@bt.action
|
|
59
|
+
async def assess_threat(bb) -> Status:
|
|
60
|
+
# Analyze threat level
|
|
61
|
+
return Status.SUCCESS if bb.threat_level > 5 else Status.FAILURE
|
|
62
|
+
|
|
63
|
+
@bt.action
|
|
64
|
+
async def engage_countermeasures(bb) -> Status:
|
|
65
|
+
# Respond to threat
|
|
66
|
+
return Status.SUCCESS
|
|
67
|
+
|
|
68
|
+
@bt.root
|
|
69
|
+
@bt.sequence
|
|
70
|
+
def root():
|
|
71
|
+
yield assess_threat
|
|
72
|
+
yield engage_countermeasures
|
|
73
|
+
|
|
74
|
+
# Run the behavior tree
|
|
75
|
+
runner = Runner(ThreatResponse, bb=blackboard)
|
|
76
|
+
await runner.tick_until_complete()
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Petri Net (Hypha)
|
|
80
|
+
|
|
81
|
+
Model workflows with colored Petri nets:
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
from mycorrhizal.hypha.core import pn, Runner, PlaceType
|
|
85
|
+
|
|
86
|
+
@pn.net
|
|
87
|
+
def ProcessingNet(builder):
|
|
88
|
+
# Define places
|
|
89
|
+
pending = builder.place("pending", type=PlaceType.QUEUE)
|
|
90
|
+
processed = builder.place("processed", type=PlaceType.QUEUE)
|
|
91
|
+
|
|
92
|
+
# Define transitions
|
|
93
|
+
@builder.transition()
|
|
94
|
+
async def process(consumed, bb, timebase):
|
|
95
|
+
for token in consumed:
|
|
96
|
+
result = await handle(token)
|
|
97
|
+
yield {processed: result}
|
|
98
|
+
|
|
99
|
+
# Wire the net
|
|
100
|
+
builder.arc(pending, process).arc(processed)
|
|
101
|
+
|
|
102
|
+
# Run the Petri net
|
|
103
|
+
runner = Runner(ProcessingNet, bb=blackboard)
|
|
104
|
+
await runner.start(timebase)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Finite State Machine (Septum)
|
|
108
|
+
|
|
109
|
+
Build stateful components with FSMs:
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
from mycorrhizal.septum.core import septum, StateMachine, LabeledTransition
|
|
113
|
+
|
|
114
|
+
@septum.state()
|
|
115
|
+
def IdleState():
|
|
116
|
+
@septum.on_state
|
|
117
|
+
async def on_state(ctx):
|
|
118
|
+
if ctx.msg == "start":
|
|
119
|
+
return Events.START
|
|
120
|
+
return None
|
|
121
|
+
|
|
122
|
+
@septum.transitions
|
|
123
|
+
def transitions():
|
|
124
|
+
return [
|
|
125
|
+
LabeledTransition(Events.START, ProcessingState),
|
|
126
|
+
]
|
|
127
|
+
|
|
128
|
+
# Create and run the FSM
|
|
129
|
+
fsm = StateMachine(initial_state=IdleState, common_data={})
|
|
130
|
+
await fsm.initialize()
|
|
131
|
+
fsm.send_message("start")
|
|
132
|
+
await fsm.tick()
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Key Features
|
|
136
|
+
|
|
137
|
+
### Shared Infrastructure
|
|
138
|
+
|
|
139
|
+
All DSLs use common building blocks:
|
|
140
|
+
|
|
141
|
+
* **Blackboards** - Typed shared state using Pydantic models
|
|
142
|
+
* **Interfaces** - Decorator-based access control for blackboard fields
|
|
143
|
+
* **Timebase** - Abstract time for simulation and testing
|
|
144
|
+
|
|
145
|
+
### Composition
|
|
146
|
+
|
|
147
|
+
Combine DSLs to model complex systems:
|
|
148
|
+
|
|
149
|
+
* Embed behavior trees in Petri net transitions
|
|
150
|
+
* Run state machines within behavior tree actions
|
|
151
|
+
* Use Petri nets to orchestrate FSM-based components
|
|
152
|
+
|
|
153
|
+
### Observability
|
|
154
|
+
|
|
155
|
+
The Spores module provides OCEL-compliant logging:
|
|
156
|
+
|
|
157
|
+
* Automatic event extraction from DSL execution
|
|
158
|
+
* Object lifecycle tracking
|
|
159
|
+
* Transport layer for custom backends
|
|
160
|
+
|
|
161
|
+
## Examples
|
|
162
|
+
|
|
163
|
+
The repository contains comprehensive examples:
|
|
164
|
+
|
|
165
|
+
* `examples/hypha/` - Petri net patterns
|
|
166
|
+
* `examples/rhizomorph/` - Behavior tree patterns
|
|
167
|
+
* `examples/septum/` - State machine patterns
|
|
168
|
+
* `examples/spores/` - Event logging integration
|
|
169
|
+
* `examples/interfaces/` - Type-safe blackboard access
|
|
170
|
+
|
|
171
|
+
Run examples with:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
uv run python examples/hypha/minimal_hypha_demo.py
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
See [examples/README.md](https://github.com/Jeff-Ciesielski/mycorrhizal/tree/main/examples/) for a complete guide.
|
|
178
|
+
|
|
179
|
+
## Visualization
|
|
180
|
+
|
|
181
|
+
All three DSLs support Mermaid diagram export for documentation and debugging. You can generate diagrams programmatically:
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
# Behavior Tree
|
|
185
|
+
diagram = MyTree.to_mermaid()
|
|
186
|
+
|
|
187
|
+
# Petri Net
|
|
188
|
+
diagram = MyNet.to_mermaid()
|
|
189
|
+
|
|
190
|
+
# Finite State Machine
|
|
191
|
+
from mycorrhizal.septum.util import to_mermaid
|
|
192
|
+
diagram = to_mermaid(fsm)
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Example Diagrams
|
|
196
|
+
|
|
197
|
+
**Behavior Tree (Rhizomorph)** - A threat response system with decorators:
|
|
198
|
+
|
|
199
|
+
```mermaid
|
|
200
|
+
flowchart TD
|
|
201
|
+
N1["Selector<br/>root"]
|
|
202
|
+
N1 --> N2
|
|
203
|
+
N2["Subtree<br/>Engage"]
|
|
204
|
+
N2 --> N3
|
|
205
|
+
N3["Sequence<br/>engage_threat"]
|
|
206
|
+
N3 --> N4
|
|
207
|
+
N4((CONDITION<br/>threat_detected))
|
|
208
|
+
N3 --> N5
|
|
209
|
+
N5["Decor<br/>Failer(Gate(cond=battery_ok)(Timeout(0.12s)(engage)))"]
|
|
210
|
+
N5 --> N6
|
|
211
|
+
N6["Decor<br/>Gate(cond=battery_ok)(Timeout(0.12s)(engage))"]
|
|
212
|
+
N6 --> N7
|
|
213
|
+
N7["Decor<br/>Timeout(0.12s)(engage)"]
|
|
214
|
+
N7 --> N8
|
|
215
|
+
N8((ACTION<br/>engage))
|
|
216
|
+
N1 --> N9
|
|
217
|
+
N9["Sequence<br/>patrol"]
|
|
218
|
+
N9 --> N10
|
|
219
|
+
N10((CONDITION<br/>has_waypoints))
|
|
220
|
+
N9 --> N11
|
|
221
|
+
N11((ACTION<br/>go_to_next))
|
|
222
|
+
N9 --> N12
|
|
223
|
+
N12["Decor<br/>Succeeder(Retry(3)(Timeout(1.0s)(scan_area)))"]
|
|
224
|
+
N12 --> N13
|
|
225
|
+
N13["Decor<br/>Retry(3)(Timeout(1.0s)(scan_area))"]
|
|
226
|
+
N13 --> N14
|
|
227
|
+
N14["Decor<br/>Timeout(1.0s)(scan_area)"]
|
|
228
|
+
N14 --> N15
|
|
229
|
+
N15((ACTION<br/>scan_area))
|
|
230
|
+
N1 --> N16
|
|
231
|
+
N16["Decor<br/>Failer(RateLimit(0.200000s)(telemetry_push))"]
|
|
232
|
+
N16 --> N17
|
|
233
|
+
N17["Decor<br/>RateLimit(0.200000s)(telemetry_push)"]
|
|
234
|
+
N17 --> N18
|
|
235
|
+
N18((ACTION<br/>telemetry_push))
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
**Petri Net (Hypha)** - A task processing system with error handling:
|
|
239
|
+
|
|
240
|
+
```mermaid
|
|
241
|
+
graph TD
|
|
242
|
+
subgraph TaskProcessingSystem.TaskGen
|
|
243
|
+
TaskProcessingSystem.TaskGen.source(("[INPUT]</br>TaskProcessingSystem.TaskGen.source"))
|
|
244
|
+
end
|
|
245
|
+
subgraph TaskProcessingSystem.TaskProc
|
|
246
|
+
TaskProcessingSystem.TaskProc.input(("TaskProcessingSystem.TaskProc.input"))
|
|
247
|
+
TaskProcessingSystem.TaskProc.processing(("TaskProcessingSystem.TaskProc.processing"))
|
|
248
|
+
TaskProcessingSystem.TaskProc.completed(("TaskProcessingSystem.TaskProc.completed"))
|
|
249
|
+
TaskProcessingSystem.TaskProc.failed(("TaskProcessingSystem.TaskProc.failed"))
|
|
250
|
+
TaskProcessingSystem.TaskProc.take_to_processing[TaskProcessingSystem.TaskProc.take_to_processing]
|
|
251
|
+
TaskProcessingSystem.TaskProc.do_processing[TaskProcessingSystem.TaskProc.do_processing]
|
|
252
|
+
TaskProcessingSystem.TaskProc.input --> TaskProcessingSystem.TaskProc.take_to_processing
|
|
253
|
+
TaskProcessingSystem.TaskProc.take_to_processing --> TaskProcessingSystem.TaskProc.processing
|
|
254
|
+
TaskProcessingSystem.TaskProc.processing --> TaskProcessingSystem.TaskProc.do_processing
|
|
255
|
+
TaskProcessingSystem.TaskProc.do_processing --> TaskProcessingSystem.TaskProc.completed
|
|
256
|
+
TaskProcessingSystem.TaskProc.do_processing --> TaskProcessingSystem.TaskProc.failed
|
|
257
|
+
end
|
|
258
|
+
subgraph TaskProcessingSystem.Notify
|
|
259
|
+
TaskProcessingSystem.Notify.input(("TaskProcessingSystem.Notify.input"))
|
|
260
|
+
TaskProcessingSystem.Notify.email_sink(("[OUTPUT]</br>TaskProcessingSystem.Notify.email_sink"))
|
|
261
|
+
TaskProcessingSystem.Notify.sms_sink(("[OUTPUT]</br>TaskProcessingSystem.Notify.sms_sink"))
|
|
262
|
+
TaskProcessingSystem.Notify.log_sink(("[OUTPUT]</br>TaskProcessingSystem.Notify.log_sink"))
|
|
263
|
+
TaskProcessingSystem.Notify.NotificationFork[TaskProcessingSystem.Notify.NotificationFork]
|
|
264
|
+
TaskProcessingSystem.Notify.input --> TaskProcessingSystem.Notify.NotificationFork
|
|
265
|
+
TaskProcessingSystem.Notify.NotificationFork --> TaskProcessingSystem.Notify.email_sink
|
|
266
|
+
TaskProcessingSystem.Notify.NotificationFork --> TaskProcessingSystem.Notify.sms_sink
|
|
267
|
+
TaskProcessingSystem.Notify.NotificationFork --> TaskProcessingSystem.Notify.log_sink
|
|
268
|
+
end
|
|
269
|
+
subgraph TaskProcessingSystem.ErrorHandle
|
|
270
|
+
TaskProcessingSystem.ErrorHandle.input(("TaskProcessingSystem.ErrorHandle.input"))
|
|
271
|
+
TaskProcessingSystem.ErrorHandle.error_log(("[OUTPUT]</br>TaskProcessingSystem.ErrorHandle.error_log"))
|
|
272
|
+
TaskProcessingSystem.ErrorHandle.ErrorForward[TaskProcessingSystem.ErrorHandle.ErrorForward]
|
|
273
|
+
TaskProcessingSystem.ErrorHandle.input --> TaskProcessingSystem.ErrorHandle.ErrorForward
|
|
274
|
+
TaskProcessingSystem.ErrorHandle.ErrorForward --> TaskProcessingSystem.ErrorHandle.error_log
|
|
275
|
+
end
|
|
276
|
+
TaskProcessingSystem.completion_tracker(("[OUTPUT]</br>TaskProcessingSystem.completion_tracker"))
|
|
277
|
+
TaskProcessingSystem.forward_source_to_input[TaskProcessingSystem.forward_source_to_input]
|
|
278
|
+
TaskProcessingSystem.CompletionFork[TaskProcessingSystem.CompletionFork]
|
|
279
|
+
TaskProcessingSystem.FailureFork[TaskProcessingSystem.FailureFork]
|
|
280
|
+
TaskProcessingSystem.TaskGen.source --> TaskProcessingSystem.forward_source_to_input
|
|
281
|
+
TaskProcessingSystem.forward_source_to_input --> TaskProcessingSystem.TaskProc.input
|
|
282
|
+
TaskProcessingSystem.TaskProc.completed --> TaskProcessingSystem.CompletionFork
|
|
283
|
+
TaskProcessingSystem.CompletionFork --> TaskProcessingSystem.Notify.input
|
|
284
|
+
TaskProcessingSystem.CompletionFork --> TaskProcessingSystem.completion_tracker
|
|
285
|
+
TaskProcessingSystem.TaskProc.failed --> TaskProcessingSystem.FailureFork
|
|
286
|
+
TaskProcessingSystem.FailureFork --> TaskProcessingSystem.ErrorHandle.input
|
|
287
|
+
TaskProcessingSystem.FailureFork --> TaskProcessingSystem.completion_tracker
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
**Finite State Machine (Septum)** - A simple idle/processing/done workflow:
|
|
291
|
+
|
|
292
|
+
```mermaid
|
|
293
|
+
flowchart TD
|
|
294
|
+
start((start)) --> S1
|
|
295
|
+
S1[IdleState]
|
|
296
|
+
S1 -->|"START"| S2
|
|
297
|
+
S1 -->|"QUIT"| S3
|
|
298
|
+
S2[ProcessingState]
|
|
299
|
+
S2 -->|"DONE"| S1
|
|
300
|
+
S3[DoneState (**terminal**)]
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
## Documentation
|
|
304
|
+
|
|
305
|
+
Full documentation is available at [https://mycorrhizal.readthedocs.io](https://mycorrhizal.readthedocs.io)
|
|
306
|
+
|
|
307
|
+
## Development
|
|
308
|
+
|
|
309
|
+
```bash
|
|
310
|
+
# Install dependencies
|
|
311
|
+
uv pip install -e ".[dev]"
|
|
312
|
+
|
|
313
|
+
# Run tests
|
|
314
|
+
pytest
|
|
315
|
+
|
|
316
|
+
# Run with coverage
|
|
317
|
+
pytest --cov=src/mycorrhizal --cov-report=html
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
## Project Status
|
|
321
|
+
|
|
322
|
+
This is a 0.1.0 release. The core APIs are stable and well-tested, but some features are still in development:
|
|
323
|
+
|
|
324
|
+
* Current: Four DSLs with decorator-based syntax
|
|
325
|
+
* Current: Comprehensive examples and tests
|
|
326
|
+
* Planned: Cross-DSL interoperability layer
|
|
327
|
+
* Planned: Enhanced composition patterns
|
|
328
|
+
|
|
329
|
+
## License
|
|
330
|
+
|
|
331
|
+
MIT
|
|
332
|
+
|
|
333
|
+
## Author
|
|
334
|
+
|
|
335
|
+
Jeff Ciesielski
|