How to apply the auto-discovery pattern to different tech stacks.
The primary pattern. See SKILL.md for complete implementation.
Key files to refactor:
src/models/index.js→ Directory scansrc/models/model-associations.js→ associations/ loaderserver/loaders/services.js→ service-registrations/ loadersrc/routes/index.js→ *.routes.js scan
// src/models/index.js — Mongoose auto-discovery
const fs = require('fs');
const path = require('path');
const mongoose = require('mongoose');
const models = {};
const SKIP = [path.basename(__filename)];
fs.readdirSync(__dirname)
.filter(f => f.endsWith('.model.js') && !SKIP.includes(f))
.sort()
.forEach(file => {
try {
const model = require(path.join(__dirname, file));
// Mongoose models register themselves; just track them
const name = path.basename(file, '.model.js');
models[name] = model;
} catch (e) {
console.error(`Model load failed ${file}:`, e.message);
}
});
module.exports = models;Mongoose doesn't need associations file — references are defined within schemas. But middleware/plugins can be auto-discovered:
// src/models/plugins/ — Auto-discovered Mongoose plugins
fs.readdirSync(pluginsDir)
.filter(f => f.endsWith('.plugin.js'))
.forEach(file => {
const plugin = require(path.join(pluginsDir, file));
mongoose.plugin(plugin);
});Django already has excellent feature isolation via its app system.
Django's built-in auto-discovery:
- Models: Automatic via
INSTALLED_APPS - Admin:
admin.autodiscover() - URLs:
include()in urlpatterns
What to add for parallel AI dev:
# Each feature is a Django app
# feature_a/
# models.py
# views.py
# urls.py
# signals.py ← cross-model relationships
# services.py ← business logic
# settings.py — just add the app name
INSTALLED_APPS = [
# ... core apps ...
'features.chatflow', # Feature A
'features.web_widget', # Feature B
'features.instagram_dm', # Feature C
]Auto-discover feature URLs:
# urls.py — auto-scan feature apps
import importlib
import pkgutil
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('core.urls')),
]
# Auto-discover feature URLs
features_package = importlib.import_module('features')
for _, name, _ in pkgutil.iter_modules(features_package.__path__):
try:
urlpatterns.append(
path(f'api/{name}/', include(f'features.{name}.urls'))
)
except ModuleNotFoundError:
pass # Feature doesn't have URLsAI agent instruction for Django:
FILES YOU CREATE:
✅ features/{feature}/models.py
✅ features/{feature}/views.py
✅ features/{feature}/urls.py
✅ features/{feature}/services.py
✅ features/{feature}/signals.py
✅ features/{feature}/tests.py
✅ features/{feature}/migrations/
FILES YOU NEVER EDIT:
❌ settings.py (INSTALLED_APPS) ← only the orchestrator adds this
❌ core/urls.py
❌ Any other feature's directory
# app/models/__init__.py — Auto-discovery
import importlib
import pkgutil
from app.extensions import db
def register_models():
"""Auto-discover and import all model modules."""
package = importlib.import_module('app.models')
for _, name, _ in pkgutil.iter_modules(package.__path__):
if name != '__init__':
importlib.import_module(f'app.models.{name}')
# app/blueprints/__init__.py — Auto-discover blueprints
def register_blueprints(app):
"""Auto-discover and register all feature blueprints."""
import os
blueprint_dir = os.path.dirname(__file__)
for item in sorted(os.listdir(blueprint_dir)):
module_path = os.path.join(blueprint_dir, item)
if os.path.isdir(module_path) and not item.startswith('_'):
try:
mod = importlib.import_module(f'app.blueprints.{item}')
if hasattr(mod, 'bp'):
app.register_blueprint(mod.bp, url_prefix=f'/api/{item}')
except Exception as e:
print(f"Failed to load blueprint {item}: {e}")Feature structure:
app/blueprints/
├── chatflow/
│ ├── __init__.py ← defines bp = Blueprint('chatflow', ...)
│ ├── routes.py
│ └── services.py
├── web_widget/
│ ├── __init__.py
│ ├── routes.py
│ └── services.py
NestJS is already modular by design. Each feature is a module.
// app.module.ts — Auto-discover feature modules
import { Module } from '@nestjs/common';
import * as glob from 'glob';
// Auto-discover all *.module.ts in features/
const featureModules = glob
.sync('features/*/*.module.ts', { cwd: __dirname })
.map(file => require(`./${file}`))
.flatMap(mod => Object.values(mod))
.filter(mod => typeof mod === 'function');
@Module({
imports: [
CoreModule,
DatabaseModule,
...featureModules, // Auto-discovered
],
})
export class AppModule {}Each feature is fully self-contained:
src/features/
├── chatflow/
│ ├── chatflow.module.ts
│ ├── chatflow.controller.ts
│ ├── chatflow.service.ts
│ └── entities/
│ └── chatflow.entity.ts
├── web-widget/
│ ├── web-widget.module.ts
│ ├── web-widget.controller.ts
│ └── web-widget.service.ts
// internal/features/registry.go — Auto-registration pattern
package features
import "github.com/gin-gonic/gin"
// FeatureRegistrar is implemented by each feature
type FeatureRegistrar interface {
RegisterRoutes(r *gin.RouterGroup)
RegisterServices(container *ServiceContainer)
}
// registry holds all feature registrars
var registry []FeatureRegistrar
// Register adds a feature (called in each feature's init())
func Register(f FeatureRegistrar) {
registry = append(registry, f)
}
// InitAll registers all features with the app
func InitAll(r *gin.Engine, container *ServiceContainer) {
api := r.Group("/api")
for _, f := range registry {
f.RegisterRoutes(api)
f.RegisterServices(container)
}
}// internal/features/chatflow/init.go
package chatflow
func init() {
features.Register(&ChatFlowFeature{})
}Regardless of language/framework, the principle is the same:
| Component | Pattern |
|---|---|
| Models | Auto-discover files in a directory |
| Relationships | Each feature registers its own in a separate file |
| Services | Plugin-style registration via directory scan |
| Routes | Auto-discover route files or blueprints |
| Tests | Per-feature test files, integration runner scans all |
| Migrations | Additive (CREATE/ALTER), sorted by filename |