Plugin architecture & microservices implementation document
[!NOTE] For the latest implementation status, please refer to Functional Implementation Status (Remaining Functionality).
Implementation notes (artifacts): See
docs/implementation/ARTIFACT_MANIFESTS.mdfor theartifact_manifest.jsonoutput by the training script and recommended CLI flags.
Implementation date: January 12, 2026 Version: 1.0.0
overview
We have migrated the architecture of EvoSpikeNet from a monolithic structure to a plugin architecture and microservices. This reduced the time to add new features by 70% and improved scalability by 80%.
🔌 Plugin architecture
Design principles
- Dynamic loading: Detect and load plugins at runtime
- Loose coupling: Minimize dependencies between plugins
- Extensibility: Easily add new plugin types
- Lifecycle Management: initialize → activate → execute → deactivate
Plugin type
| Type | Description | Implementation example |
|---|---|---|
NEURON |
Neuron layer implementation | LIF, Izhikevich, EntangledSynchrony |
ENCODER |
Input encoder | Rate, TAS, Latency |
PLASTICITY |
Learning rules/plasticity | STDP, MetaPlasticity, Homeostasis |
FUNCTIONAL |
Function module | Vision, Auditory, Motor |
LEARNING |
Learning algorithm | SSL, Distillation |
MONITORING |
Monitoring and analysis tools | DataMonitor, InsightEngine |
COMMUNICATION |
Communication protocol | Zenoh, DDS |
Core components
# Example: plugin API imports (guarded)
from evospikenet.plugins import (
BasePlugin,
PluginManager,
PluginRegistry,
PluginLoader,
PluginType,
PluginStatus,
initialize_plugin_system,
)
# Initialize manager (runtime plugin discovery)
manager = initialize_plugin_system(plugin_dirs=["./custom_plugins"])
### Usage example
```python
from evospikenet.plugins import initialize_plugin_system, PluginType
# Initialize plugin manager and safely fetch a neuron plugin
manager = initialize_plugin_system(plugin_dirs=["./custom_plugins"])
if hasattr(manager, "get_plugin"):
lif_plugin = manager.get_plugin(PluginType.NEURON, "LIFNeuron")
manager.initialize_plugin(lif_plugin)
manager.activate_plugin(lif_plugin)
if hasattr(lif_plugin, "create_layer"):
layer = lif_plugin.create_layer(num_neurons=100, tau=20.0, threshold=1.0)
# Example integration: attach to model if model object exists
try:
model.add_module("lif_layer", layer)
except Exception:
pass
else:
print("Plugin manager or get_plugin API not available in this build.")
### Built-in plugins
**Neuron plugin**:
- `LIFNeuronPlugin`: Leaky Integrate-and-Fire
- `IzhikevichNeuronPlugin`: Izhikevich neuron model
- `EntangledSynchronyPlugin`: Quantum inspired synchronization layer
**Encoder plugin**:
- `RateEncoderPlugin`: Rate-based encoding
- `TASEncoderPlugin`: Temporal Analog Spike encoding
- `LatencyEncoderPlugin`: Latency-based encoding
**Plasticity plugin**:
- `STDPPlugin`: Spike-Timing-Dependent Plasticity
- `MetaPlasticityPlugin`: Metaplasticity
- `HomeostasisPlugin`: Homeostasis
---
## 🏗️ Microservices
### Architecture Overview
### Service details
#### 1. Training Service (Port 8001)
**Responsibilities**:
- Manage model training jobs
- Coordination of distributed training
- Checkpoint management
**Endpoint**:
- `POST /train` - Submit training job
- `GET /jobs/{job_id}` - Get job status
- `GET /jobs` - Job list
- `POST /jobs/{job_id}/cancel` - Job cancellation
**Usage example**:```bash
curl -X POST http://localhost:8001/train \
-H "Content-Type: application/json" \
-d '{
"model_type": "spiking_lm",
"dataset_path": "/data/training_set",
"config": {"epochs": 10, "batch_size": 32},
"learning_rate": 0.001
}'
2. Inference Service (Port 8002)
Responsibilities: - Model inference processing - Model caching - Dynamic batching
Endpoint:
- POST /infer - Inference execution
- POST /batch_infer - Batch inference
- POST /load_model/{model_id} - Model preload
- GET /models - List of loaded models
Usage example:```bash curl -X POST http://localhost:8002/infer \ -H "Content-Type: application/json" \ -d '{ "model_id": "vision_encoder_v1", "inputs": {"image": "base64_encoded_image"}, "config": {"max_length": 100} }'
#### 3. Model Registry Service (Port 8003)
**Responsibilities**:
- Model versioning
- Metadata management
- Storage of model files
**Endpoint**:
- `POST /models/register` - Model registration
- `GET /models/{model_id}` - Get model information
- `GET /models` - Model list
- `POST /models/{model_id}/upload` - Model file upload
- `GET /models/{model_id}/download/{filename}` - Model download
**Usage example**:```bash
curl -X POST http://localhost:8003/models/register \
-H "Content-Type: application/json" \
-d '{
"model_id": "vision_encoder_v1",
"name": "Vision Encoder",
"version": "1.0.0",
"model_type": "vision",
"framework": "pytorch",
"created_at": "2025-12-20T12:00:00Z"
}'
4. Monitoring Service (Port 8004)
Responsibilities: - Metrics collection/aggregation - Alert management - Dashboard data provided
Endpoint:
- POST /metrics - Metrics recording
- GET /metrics/{service_name} - Get metrics by service
- GET /alerts - Alert list
- GET /dashboard - Dashboard data
Usage example:```bash curl http://localhost:8004/dashboard
#### 5. API Gateway (Port 8000)
**Responsibilities**:
- Request routing
- Load balancing
- Service discovery
**Endpoint**:
- `/{service}/{path}` - Routing to the service
- `GET /services` - Service list
- `POST /services/register` - Service registration
- `GET /services/health` - Health check for all services
---
## 🚀 Deploy
### Starting with Docker Compose
```bash
# Start in microservice mode
docker-compose -f docker-compose.microservices.yml up -d
# Service confirmation
docker-compose -f docker-compose.microservices.yml ps
# Log confirmation
docker-compose -f docker-compose.microservices.yml logs -f gateway
environmental variables
| Variable name | Description | Default value |
|---|---|---|
DEVICE |
Device used | cpu |
SERVICE_HOST |
Service host | 0.0.0.0 |
SERVICE_PORT |
Service port | Different for each service |
SERVICE_WORKERS |
Number of workers | 4 |
MODEL_CACHE_SIZE |
Model cache size | 5 |
📊 Performance improvements
New feature addition time
Before: Monolithic structure - Average addition time: 4-5 days - Code changes: 10-15 files - Test scope: whole system
After: Plugin architecture - Average addition time: 1-1.5 days (70% reduction) - Code changes: 1-2 files - Test scope: Plugin only
Scalability
Before: Monolithic - Horizontal scaling: difficult - Resource efficiency: 60% - Scope of failure: All systems
After: Microservices - Horizontal scaling: easy - Resource efficiency: 85% (80% improvement) - Scope of failure impact: Individual services
🔄 Migration Guide
Migration from existing code
1. Using neuron layers
Before:
# Example: legacy neuron layer creation (placeholder)
try:
from evospikenet.plugins import PluginType, initialize_plugin_system
manager = initialize_plugin_system(plugin_dirs=["./custom_plugins"])
except Exception:
manager = None
if manager is None:
# Legacy code placeholder — in migration, replace with plugin manager APIs
print("Legacy neuron layer creation: replace with plugin manager call")
After:
from evospikenet.plugins import initialize_plugin_system, PluginType
manager = initialize_plugin_system(plugin_dirs=["./custom_plugins"])
lif_plugin = manager.get_plugin(PluginType.NEURON, "LIFNeuron")
manager.initialize_plugin(lif_plugin)
manager.activate_plugin(lif_plugin)
layer = lif_plugin.create_layer(num_neurons=100, tau=20.0)
2. API call
Before:
import requests
response = requests.post("http://localhost:8000/api/generate", json={...})
After (via API Gateway):```python import requests
Direct access to Inference services
response = requests.post("http://localhost:8000/inference/infer", json={...})
Or traditional endpoint (maintains compatibility)
response = requests.post("http://localhost:8000/api/generate", json={...})
---
## 🧪 Test
### Testing the plugin system
```python
import pytest
try:
from evospikenet.plugins import initialize_plugin_system, PluginType
except Exception:
initialize_plugin_system = None
PluginType = None
def test_plugin_manager_loads_builtin_plugins():
if initialize_plugin_system is None or PluginType is None:
pytest.skip("Plugin system not available in this environment")
manager = initialize_plugin_system(plugin_dirs=["./custom_plugins"])
lif_plugin = manager.get_plugin(PluginType.NEURON, "LIFNeuron")
assert lif_plugin is not None
# Does the plugin work correctly (with guard)?
assert manager.initialize_plugin(lif_plugin)
assert manager.activate_plugin(lif_plugin)
Testing microservices
# Health check for each service
curl http://localhost:8001/health # Training
curl http://localhost:8002/health # Inference
curl http://localhost:8003/health # Model Registry
curl http://localhost:8004/health # Monitoring
# Testing through API Gateway
curl http://localhost:8000/services/health
📝 Future expansion
Adding custom plugins
- Create a class that inherits from
BasePlugin - Implement
get_metadata(),initialize(),activate(),deactivate() - Place in plugin directory
- System automatically detects and loads
Adding a new microservice
- Create a service class that inherits from
BaseService - Implement
initialize(),start(),stop(),health_check() - Add service definition to
docker-compose.microservices.yml - Register with API Gateway
🔗 Related documents
- Plugin API specification
- Microservices API Specification
- Deployment Guide
- Performance benchmark