2025-12-11 21:50:42 +00:00
# Orchestrator Integration Model - Deep Dive
**Date:** 2025-10-01
**Status:** Clarification Document
**Related:** [Multi-Repo Strategy ](multi-repo-strategy.md ), [Hybrid Orchestrator v3.0 ](../user/hybrid-orchestrator.md )
## Executive Summary
This document clarifies **how the Rust orchestrator integrates with Nushell core** in both monorepo and multi-repo architectures. The orchestrator is a **critical performance layer** that coordinates Nushell business logic execution, solving deep call stack limitations while preserving all existing functionality.
---
## Current Architecture (Hybrid Orchestrator v3.0)
### The Problem Being Solved
**Original Issue:**
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
Deep call stack in Nushell (template.nu:71)
→ "Type not supported" errors
→ Cannot handle complex nested workflows
→ Performance bottlenecks with recursive calls
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
**Solution:** Rust orchestrator provides:
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
1. **Task queue management** (file-based, reliable)
2. **Priority scheduling** (intelligent task ordering)
3. **Deep call stack elimination** (Rust handles recursion)
4. **Performance optimization** (async/await, parallel execution)
5. **State management** (workflow checkpointing)
### How It Works Today (Monorepo)
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
┌─────────────────────────────────────────────────────────────┐
│ User │
└───────────────────────────┬─────────────────────────────────┘
│ calls
↓
┌───────────────┐
│ provisioning │ (Nushell CLI)
│ CLI │
└───────┬───────┘
│
┌───────────────────┼───────────────────┐
│ │ │
↓ ↓ ↓
┌───────────────┐ ┌───────────────┐ ┌──────────────┐
│ Direct Mode │ │Orchestrated │ │ Workflow │
│ (Simple ops) │ │ Mode │ │ Mode │
└───────────────┘ └───────┬───────┘ └──────┬───────┘
│ │
↓ ↓
┌────────────────────────────────┐
│ Rust Orchestrator Service │
│ (Background daemon) │
│ │
│ • Task Queue (file-based) │
│ • Priority Scheduler │
│ • Workflow Engine │
│ • REST API Server │
└────────┬───────────────────────┘
│ spawns
↓
┌────────────────┐
│ Nushell │
│ Business Logic │
│ │
│ • servers.nu │
│ • taskservs.nu │
│ • clusters.nu │
└────────────────┘
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
### Three Execution Modes
#### Mode 1: Direct Mode (Simple Operations)
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
```bash
# No orchestrator needed
provisioning server list
provisioning env
provisioning help
# Direct Nushell execution
provisioning (CLI) → Nushell scripts → Result
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
#### Mode 2: Orchestrated Mode (Complex Operations)
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
```bash
# Uses orchestrator for coordination
provisioning server create --orchestrated
# Flow:
provisioning CLI → Orchestrator API → Task Queue → Nushell executor
↓
Result back to user
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
#### Mode 3: Workflow Mode (Batch Operations)
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
```bash
# Complex workflows with dependencies
2026-01-08 09:55:37 +00:00
provisioning workflow submit server-cluster.ncl
2025-12-11 21:50:42 +00:00
# Flow:
provisioning CLI → Orchestrator Workflow Engine → Dependency Graph
↓
Parallel task execution
↓
Nushell scripts for each task
↓
Checkpoint state
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
---
## Integration Patterns
### Pattern 1: CLI Submits Tasks to Orchestrator
**Current Implementation:**
**Nushell CLI (`core/nulib/workflows/server_create.nu` ):**
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
```nushell
# Submit server creation workflow to orchestrator
export def server_create_workflow [
infra_name: string
--orchestrated
] {
if $orchestrated {
# Submit task to orchestrator
let task = {
type: "server_create"
infra: $infra_name
params: { ... }
}
# POST to orchestrator REST API
http post http://localhost:9090/workflows/servers/create $task
} else {
# Direct execution (old way)
do-server-create $infra_name
}
}
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
**Rust Orchestrator (`platform/orchestrator/src/api/workflows.rs` ):**
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
```rust
// Receive workflow submission from Nushell CLI
#[axum::debug_handler]
async fn create_server_workflow(
State(state): State< Arc < AppState > >,
Json(request): Json< ServerCreateRequest > ,
) -> Result< Json < WorkflowResponse > , ApiError> {
// Create task
let task = Task {
id: Uuid::new_v4(),
task_type: TaskType::ServerCreate,
payload: serde_json::to_value(& request)?,
priority: Priority::Normal,
status: TaskStatus::Pending,
created_at: Utc::now(),
};
// Queue task
state.task_queue.enqueue(task).await?;
// Return immediately (async execution)
Ok(Json(WorkflowResponse {
workflow_id: task.id,
status: "queued",
}))
}
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
**Flow:**
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
User → provisioning server create --orchestrated
↓
Nushell CLI prepares task
↓
HTTP POST to orchestrator (localhost:9090)
↓
Orchestrator queues task
↓
Returns workflow ID immediately
↓
User can monitor: provisioning workflow monitor < id >
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
### Pattern 2: Orchestrator Executes Nushell Scripts
**Orchestrator Task Executor (`platform/orchestrator/src/executor.rs` ):**
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
```rust
// Orchestrator spawns Nushell to execute business logic
pub async fn execute_task(task: Task) -> Result< TaskResult > {
match task.task_type {
TaskType::ServerCreate => {
// Orchestrator calls Nushell script via subprocess
let output = Command::new("nu")
.arg("-c")
.arg(format!(
"use {}/servers/create.nu; create-server '{}'",
PROVISIONING_LIB_PATH,
task.payload.infra_name
))
.output()
.await?;
// Parse Nushell output
let result = parse_nushell_output(&output)?;
Ok(TaskResult {
task_id: task.id,
status: if result.success { "completed" } else { "failed" },
output: result.data,
})
}
// Other task types...
}
}
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
**Flow:**
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
Orchestrator task queue has pending task
↓
Executor picks up task
↓
Spawns Nushell subprocess: nu -c "use servers/create.nu; create-server 'wuji'"
↓
Nushell executes business logic
↓
Returns result to orchestrator
↓
Orchestrator updates task status
↓
User monitors via: provisioning workflow status < id >
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
### Pattern 3: Bidirectional Communication
**Nushell Calls Orchestrator API:**
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
```nushell
# Nushell script checks orchestrator status during execution
export def check-orchestrator-health [] {
let response = (http get http://localhost:9090/health)
if $response.status != "healthy" {
error make { msg: "Orchestrator not available" }
}
$response
}
# Nushell script reports progress to orchestrator
export def report-progress [task_id: string, progress: int] {
http post http://localhost:9090/tasks/$task_id/progress {
progress: $progress
status: "in_progress"
}
}
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
**Orchestrator Monitors Nushell Execution:**
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
```rust
// Orchestrator tracks Nushell subprocess
pub async fn execute_with_monitoring(task: Task) -> Result< TaskResult > {
let mut child = Command::new("nu")
.arg("-c")
.arg(& task.script)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;
// Monitor stdout/stderr in real-time
let stdout = child.stdout.take().unwrap();
tokio::spawn(async move {
let reader = BufReader::new(stdout);
let mut lines = reader.lines();
while let Some(line) = lines.next_line().await.unwrap() {
// Parse progress updates from Nushell
if line.contains("PROGRESS:") {
update_task_progress(&line);
}
}
});
// Wait for completion with timeout
let result = tokio::time::timeout(
Duration::from_secs(3600),
child.wait()
).await??;
Ok(TaskResult::from_exit_status(result))
}
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
---
## Multi-Repo Architecture Impact
### Repository Split Doesn't Change Integration Model
**In Multi-Repo Setup:**
**Repository: `provisioning-core` **
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
- Contains: Nushell business logic
- Installs to: `/usr/local/lib/provisioning/`
- Package: `provisioning-core-3.2.1.tar.gz`
**Repository: `provisioning-platform` **
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
- Contains: Rust orchestrator
- Installs to: `/usr/local/bin/provisioning-orchestrator`
- Package: `provisioning-platform-2.5.3.tar.gz`
**Runtime Integration (Same as Monorepo):**
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
User installs both packages:
provisioning-core-3.2.1 → /usr/local/lib/provisioning/
provisioning-platform-2.5.3 → /usr/local/bin/provisioning-orchestrator
Orchestrator expects core at: /usr/local/lib/provisioning/
Core expects orchestrator at: http://localhost:9090/
No code dependencies, just runtime coordination!
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
### Configuration-Based Integration
**Core Package (`provisioning-core` ) config:**
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
```toml
# /usr/local/share/provisioning/config/config.defaults.toml
[orchestrator]
enabled = true
endpoint = "http://localhost:9090"
timeout = 60
auto_start = true # Start orchestrator if not running
[execution]
default_mode = "orchestrated" # Use orchestrator by default
fallback_to_direct = true # Fall back if orchestrator down
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
**Platform Package (`provisioning-platform` ) config:**
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
```toml
# /usr/local/share/provisioning/platform/config.toml
[orchestrator]
host = "127.0.0.1"
port = 8080
data_dir = "/var/lib/provisioning/orchestrator"
[executor]
nushell_binary = "nu" # Expects nu in PATH
provisioning_lib = "/usr/local/lib/provisioning"
max_concurrent_tasks = 10
task_timeout_seconds = 3600
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
### Version Compatibility
**Compatibility Matrix (`provisioning-distribution/versions.toml` ):**
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
```toml
[compatibility.platform."2.5.3"]
core = "^3.2" # Platform 2.5.3 compatible with core 3.2.x
min-core = "3.2.0"
api-version = "v1"
[compatibility.core."3.2.1"]
platform = "^2.5" # Core 3.2.1 compatible with platform 2.5.x
min-platform = "2.5.0"
orchestrator-api = "v1"
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
---
## Execution Flow Examples
### Example 1: Simple Server Creation (Direct Mode)
**No Orchestrator Needed:**
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
```bash
provisioning server list
# Flow:
CLI → servers/list.nu → Query state → Return results
(Orchestrator not involved)
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
### Example 2: Server Creation with Orchestrator
**Using Orchestrator:**
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
```bash
provisioning server create --orchestrated --infra wuji
# Detailed Flow:
1. User executes command
↓
2. Nushell CLI (provisioning binary)
↓
3. Reads config: orchestrator.enabled = true
↓
4. Prepares task payload:
{
type: "server_create",
infra: "wuji",
params: { ... }
}
↓
5. HTTP POST → http://localhost:9090/workflows/servers/create
↓
6. Orchestrator receives request
↓
7. Creates task with UUID
↓
8. Enqueues to task queue (file-based: /var/lib/provisioning/queue/)
↓
9. Returns immediately: { workflow_id: "abc-123", status: "queued" }
↓
10. User sees: "Workflow submitted: abc-123"
↓
11. Orchestrator executor picks up task
↓
12. Spawns Nushell subprocess:
nu -c "use /usr/local/lib/provisioning/servers/create.nu; create-server 'wuji'"
↓
13. Nushell executes business logic:
2026-01-08 09:55:37 +00:00
- Reads Nickel config
2025-12-11 21:50:42 +00:00
- Calls provider API (UpCloud/AWS)
- Creates server
- Returns result
↓
14. Orchestrator captures output
↓
15. Updates task status: "completed"
↓
16. User monitors: provisioning workflow status abc-123
→ Shows: "Server wuji created successfully"
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
### Example 3: Batch Workflow with Dependencies
**Complex Workflow:**
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
```bash
2026-01-08 09:55:37 +00:00
provisioning batch submit multi-cloud-deployment.ncl
2025-12-11 21:50:42 +00:00
# Workflow contains:
- Create 5 servers (parallel)
- Install Kubernetes on servers (depends on server creation)
- Deploy applications (depends on Kubernetes)
# Detailed Flow:
2026-01-08 09:55:37 +00:00
1. CLI submits Nickel workflow to orchestrator
2025-12-11 21:50:42 +00:00
↓
2. Orchestrator parses workflow
↓
3. Builds dependency graph using petgraph (Rust)
↓
4. Topological sort determines execution order
↓
5. Creates tasks for each operation
↓
6. Executes in parallel where possible:
[Server 1] [Server 2] [Server 3] [Server 4] [Server 5]
↓ ↓ ↓ ↓ ↓
(All execute in parallel via Nushell subprocesses)
↓ ↓ ↓ ↓ ↓
└──────────┴──────────┴──────────┴──────────┘
│
↓
[All servers ready]
↓
[Install Kubernetes]
(Nushell subprocess)
↓
[Kubernetes ready]
↓
[Deploy applications]
(Nushell subprocess)
↓
[Complete]
7. Orchestrator checkpoints state at each step
↓
8. If failure occurs, can retry from checkpoint
↓
9. User monitors real-time: provisioning batch monitor < id >
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
---
2026-01-08 09:55:37 +00:00
## Why This Architecture
2025-12-11 21:50:42 +00:00
### Orchestrator Benefits
1. **Eliminates Deep Call Stack Issues**
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
```
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
Without Orchestrator:
template.nu → calls → cluster.nu → calls → taskserv.nu → calls → provider.nu
(Deep nesting causes "Type not supported" errors)
With Orchestrator:
Orchestrator → spawns → Nushell subprocess (flat execution)
(No deep nesting, fresh Nushell context for each task)
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
2. **Performance Optimization**
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
```rust
// Orchestrator executes tasks in parallel
let tasks = vec![task1, task2, task3, task4, task5];
let results = futures::future::join_all(
tasks.iter().map(|t| execute_task(t))
).await;
// 5 Nushell subprocesses run concurrently
```
2026-01-08 09:55:37 +00:00
1. **Reliable State Management**
```plaintext
2025-12-11 21:50:42 +00:00
Orchestrator maintains:
- Task queue (survives crashes)
- Workflow checkpoints (resume on failure)
- Progress tracking (real-time monitoring)
- Retry logic (automatic recovery)
```
2026-01-08 09:55:37 +00:00
1. **Clean Separation**
```plaintext
2025-12-11 21:50:42 +00:00
Orchestrator (Rust): Performance, concurrency, state
Business Logic (Nushell): Providers, taskservs, workflows
Each does what it's best at!
```
2026-01-08 09:55:37 +00:00
### Why NOT Pure Rust
2025-12-11 21:50:42 +00:00
**Question:** Why not implement everything in Rust?
**Answer:**
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
1. **Nushell is perfect for infrastructure automation:**
- Shell-like scripting for system operations
- Built-in structured data handling
- Easy template rendering
- Readable business logic
2. **Rapid iteration:**
- Change Nushell scripts without recompiling
- Community can contribute Nushell modules
- Template-based configuration generation
3. **Best of both worlds:**
- Rust: Performance, type safety, concurrency
- Nushell: Flexibility, readability, ease of use
---
## Multi-Repo Integration Example
### Installation
**User installs bundle:**
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
```bash
curl -fsSL https://get.provisioning.io | sh
# Installs:
1. provisioning-core-3.2.1.tar.gz
→ /usr/local/bin/provisioning (Nushell CLI)
→ /usr/local/lib/provisioning/ (Nushell libraries)
→ /usr/local/share/provisioning/ (configs, templates)
2. provisioning-platform-2.5.3.tar.gz
→ /usr/local/bin/provisioning-orchestrator (Rust binary)
→ /usr/local/share/provisioning/platform/ (platform configs)
3. Sets up systemd/launchd service for orchestrator
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
### Runtime Coordination
**Core package expects orchestrator:**
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
```nushell
# core/nulib/lib_provisioning/orchestrator/client.nu
# Check if orchestrator is running
export def orchestrator-available [] {
let config = (load-config)
let endpoint = $config.orchestrator.endpoint
try {
let response = (http get $"($endpoint)/health")
$response.status == "healthy"
} catch {
false
}
}
# Auto-start orchestrator if needed
export def ensure-orchestrator [] {
if not (orchestrator-available) {
if (load-config).orchestrator.auto_start {
print "Starting orchestrator..."
^provisioning-orchestrator --daemon
sleep 2sec
}
}
}
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
**Platform package executes core scripts:**
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
```rust
// platform/orchestrator/src/executor/nushell.rs
pub struct NushellExecutor {
provisioning_lib: PathBuf, // /usr/local/lib/provisioning
nu_binary: PathBuf, // nu (from PATH)
}
impl NushellExecutor {
pub async fn execute_script(& self, script: & str) -> Result< Output > {
Command::new(& self.nu_binary)
.env("NU_LIB_DIRS", & self.provisioning_lib)
.arg("-c")
.arg(script)
.output()
.await
}
pub async fn execute_module_function(
& self,
module: & str,
function: & str,
args: & [String],
) -> Result< Output > {
let script = format!(
"use {}/{}; {} {}",
self.provisioning_lib.display(),
module,
function,
args.join(" ")
);
self.execute_script(& script).await
}
}
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
---
## Configuration Examples
### Core Package Config
**`/usr/local/share/provisioning/config/config.defaults.toml` :**
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
```toml
[orchestrator]
enabled = true
endpoint = "http://localhost:9090"
timeout_seconds = 60
auto_start = true
fallback_to_direct = true
[execution]
# Modes: "direct", "orchestrated", "auto"
default_mode = "auto" # Auto-detect based on complexity
# Operations that always use orchestrator
force_orchestrated = [
"server.create",
"cluster.create",
"batch.*",
"workflow.*"
]
# Operations that always run direct
force_direct = [
"*.list",
"*.show",
"help",
"version"
]
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
### Platform Package Config
**`/usr/local/share/provisioning/platform/config.toml` :**
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
```toml
[server]
host = "127.0.0.1"
port = 8080
[storage]
backend = "filesystem" # or "surrealdb"
data_dir = "/var/lib/provisioning/orchestrator"
[executor]
max_concurrent_tasks = 10
task_timeout_seconds = 3600
checkpoint_interval_seconds = 30
[nushell]
binary = "nu" # Expects nu in PATH
provisioning_lib = "/usr/local/lib/provisioning"
env_vars = { NU_LIB_DIRS = "/usr/local/lib/provisioning" }
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
---
## Key Takeaways
### 1. **Orchestrator is Essential**
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
- Solves deep call stack problems
- Provides performance optimization
- Enables complex workflows
- NOT optional for production use
### 2. **Integration is Loose but Coordinated**
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
- No code dependencies between repos
- Runtime integration via CLI + REST API
- Configuration-driven coordination
- Works in both monorepo and multi-repo
### 3. **Best of Both Worlds**
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
- Rust: High-performance coordination
- Nushell: Flexible business logic
- Clean separation of concerns
- Each technology does what it's best at
### 4. **Multi-Repo Doesn't Change Integration**
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
- Same runtime model as monorepo
- Package installation sets up paths
- Configuration enables discovery
- Versioning ensures compatibility
---
## Conclusion
The confusing example in the multi-repo doc was **oversimplified** . The real architecture is:
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
✅ Orchestrator IS USED and IS ESSENTIAL
✅ Platform (Rust) coordinates Core (Nushell) execution
✅ Loose coupling via CLI + REST API (not code dependencies)
✅ Works identically in monorepo and multi-repo
✅ Configuration-based integration (no hardcoded paths)
2026-01-08 09:55:37 +00:00
```plaintext
2025-12-11 21:50:42 +00:00
The orchestrator provides:
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
- Performance layer (async, parallel execution)
- Workflow engine (complex dependencies)
- State management (checkpoints, recovery)
- Task queue (reliable execution)
While Nushell provides:
2026-01-08 09:55:37 +00:00
2025-12-11 21:50:42 +00:00
- Business logic (providers, taskservs, clusters)
- Template rendering (Jinja2 via nu_plugin_tera)
- Configuration management (KCL integration)
- User-facing scripting
**Multi-repo just splits WHERE the code lives, not HOW it works together.**