# M6 Implementation Plan: Multi-Dimensional Orchestration
**Goal:** Transform tools from isolated actors to hierarchical orchestrators through tool spawning and permission delegation.
**Constraint Removed:** Isolated Tools → Tool Composition with Parent-Child Relationships
**Witness Outcome:** "Tool-A spawns Tool-B with action X → Tool-B inherits Tool-A's permission level → Tool-B executes → Result flows back to Tool-A"
---
## Architecture Shift
### Before M6 (M5 State)
```typescript
// Horizontal coordination through SharedContext
data-tool.create('resource') → SharedContext
admin-tool.read('resource') ← SharedContext
// Tools are peers, coordinated by conversation
ConversationManager orchestrates all tools
Tools have no awareness of each other
```
### After M6 (Target State)
```typescript
// Hierarchical delegation through tool spawning
orchestrator-tool.execute('workflow')
→ spawns data-tool.create('resource')
→ spawns validator-tool.validate('resource')
→ returns validation result
→ returns creation result
→ aggregates results
→ returns workflow completion
// Tools can spawn child tools
// Permission flows from parent to child
// Results flow from child to parent
```
**Critical Truth:** M6 is not "add orchestration logic". M6 is "remove the constraint preventing tools from spawning tools".
---
## Task 6.1: Tool Spawning Context (CRITICAL) 🔴
**Constraint:** Tools lack factory access → Cannot spawn other tools
**Witness Outcome:** Tool receives ToolContext with registry access → Can call other tools
### Acceptance Criteria
- [ ] ToolContext includes `toolRegistry: ToolRegistry`
- [ ] ToolContext includes `conversationManager: ConversationManager`
- [ ] Tools can query available tools via `context.toolRegistry.listTools()`
- [ ] Tools can spawn child tools via `context.conversationManager.negotiate()`
- [ ] Parent-child relationship tracked in conversation state
### Implementation
**Extend ToolContext:**
```typescript
export interface ToolContext {
conversationId: string;
alignmentCheck?: AlignmentCheck;
sharedContext?: SharedContext;
toolName?: string;
args?: any;
// M6: Tool spawning capability
toolRegistry?: ToolRegistry; // Access to available tools
conversationManager?: ConversationManager; // Ability to spawn tools
parentTool?: string; // Who spawned me?
depth?: number; // Recursion depth (0 = root)
}
```
**Usage Pattern:**
```typescript
// Inside orchestrator-tool.ts
async execute(action: string, context: ToolContext): Promise<ToolResult> {
if (action === 'workflow') {
// Spawn data-tool
const result1 = await context.conversationManager.negotiate(
context.conversationId,
'create-resource',
{ name: 'data', data: { x: 1 } }
);
// Spawn validator-tool
const result2 = await context.conversationManager.negotiate(
context.conversationId,
'validate-resource',
{ name: 'data' }
);
return {
success: true,
output: { created: result1, validated: result2 }
};
}
}
```
**Completion Signal:** ✅ Tool can spawn another tool and receive result
---
## Task 6.2: Permission Inheritance (CRITICAL) 🔴
**Constraint:** Parent permissions don't flow to children → Child tools start at level 1
**Witness Outcome:** Parent at level 3 spawns child → Child inherits level 3 (or specified subset)
### Acceptance Criteria
- [ ] Child tools inherit parent's permission level by default
- [ ] Parent can specify lower permission level for child (constraint, not escalation)
- [ ] Permission delegation tracked in conversation state
- [ ] Child cannot escalate beyond parent's level
- [ ] Permission inheritance visible in `conversation:status`
### Implementation
**Permission Delegation Model:**
```typescript
interface PermissionDelegation {
parentTool: string;
childTool: string;
parentLevel: number;
delegatedLevel: number; // Must be <= parentLevel
timestamp: number;
}
interface ConversationState {
// ... existing fields
permissionDelegations?: PermissionDelegation[];
}
```
**Delegation Logic:**
```typescript
// In ConversationManager.negotiate()
if (context.parentTool) {
const parentLevel = this.getToolPermissionLevel(state, context.parentTool);
const childLevel = this.getToolPermissionLevel(state, toolName);
// Child inherits parent's level (or specified level, whichever is lower)
const effectiveLevel = Math.min(parentLevel, context.requestedLevel || parentLevel);
if (childLevel < effectiveLevel) {
// Auto-upgrade child to inherited level
state.toolPermissions[toolName] = {
level: effectiveLevel,
upgradedAt: Date.now(),
inheritedFrom: context.parentTool
};
}
}
```
**Completion Signal:** ✅ Parent level-3 spawns child → Child operates at level-3 without approval
---
## Task 6.3: Recursion Safety (CRITICAL) 🔴
**Constraint:** Unbounded recursion → Stack overflow / infinite loops
**Witness Outcome:** Tool spawning depth limited to configurable maximum (default: 5)
### Acceptance Criteria
- [ ] Maximum recursion depth enforced (default: 5, configurable)
- [ ] Depth tracked in ToolContext (`depth` field)
- [ ] Depth limit violation returns clear error
- [ ] Depth visible in conversation state
- [ ] Circular dependency detection (Tool-A → Tool-B → Tool-A)
### Implementation
**Depth Tracking:**
```typescript
// In ConversationManager.negotiate()
const depth = context.parentTool ? (context.depth || 0) + 1 : 0;
const maxDepth = 5; // Configurable
if (depth > maxDepth) {
return {
success: false,
error: `Maximum tool spawning depth exceeded (${depth} > ${maxDepth}). Possible circular dependency.`
};
}
// Pass depth to spawned tool
const childContext: ToolContext = {
...context,
parentTool: toolName,
depth: depth
};
```
**Circular Dependency Detection:**
```typescript
// Track call chain in context
const callChain = context.callChain || [];
const newCallChain = [...callChain, toolName];
if (callChain.includes(toolName)) {
return {
success: false,
error: `Circular dependency detected: ${newCallChain.join(' → ')}`
};
}
```
**Completion Signal:** ✅ Tool spawning depth 6 → Error returned, no stack overflow
---
## Task 6.4: Orchestrator Tool (IMPLEMENTATION) 🔴
**Constraint:** No tool demonstrates M6 capabilities → Cannot witness orchestration
**Witness Outcome:** orchestrator-tool composes data-tool + admin-tool into workflow
### Acceptance Criteria
- [ ] orchestrator-tool.ts created with workflow capability
- [ ] Workflow spawns multiple child tools in sequence
- [ ] Workflow aggregates child results
- [ ] Workflow demonstrates permission inheritance
- [ ] Workflow demonstrates error handling (child failure)
### Implementation
**Create orchestrator-tool.ts:**
```typescript
class OrchestratorTool extends BaseTool {
constructor() {
super({
name: 'orchestrator-tool',
version: '1.0.0',
capabilities: ['workflow', 'pipeline', 'aggregate'],
});
}
async execute(action: string, context: ToolContext): Promise<ToolResult> {
if (!context.conversationManager) {
return {
success: false,
error: 'Tool spawning not available (M6 context missing)'
};
}
switch (action) {
case 'workflow':
return this.executeWorkflow(context);
case 'pipeline':
return this.executePipeline(context);
case 'aggregate':
return this.executeAggregate(context);
default:
return {
success: false,
error: `Unknown action: ${action}`
};
}
}
private async executeWorkflow(context: ToolContext): Promise<ToolResult> {
const results = [];
// Step 1: Create resource with data-tool
const createResult = await context.conversationManager.negotiate(
context.conversationId,
'create-resource',
{ name: 'workflow-data', data: { step: 1 } }
);
results.push({ step: 'create', result: createResult });
if (!createResult.success) {
return {
success: false,
error: `Workflow failed at step 1: ${createResult.error}`
};
}
// Step 2: Validate resource with admin-tool
const validateResult = await context.conversationManager.negotiate(
context.conversationId,
'validate-resource',
{ name: 'workflow-data' }
);
results.push({ step: 'validate', result: validateResult });
if (!validateResult.success) {
return {
success: false,
error: `Workflow failed at step 2: ${validateResult.error}`
};
}
// Step 3: Read final state
const readResult = await context.conversationManager.negotiate(
context.conversationId,
'read-resource',
{ name: 'workflow-data' }
);
results.push({ step: 'read', result: readResult });
return {
success: true,
output: {
workflow: 'create-validate-read',
steps: results.length,
results: results,
message: 'Workflow completed successfully'
}
};
}
}
```
**Action Schemas:**
```typescript
actionSchemas: {
'workflow': {
params: [],
required: [],
description: 'Execute multi-step workflow (create → validate → read)'
},
'pipeline': {
params: ['steps'],
required: ['steps'],
description: 'Execute custom pipeline of tool actions'
},
'aggregate': {
params: ['actions'],
required: ['actions'],
description: 'Run multiple actions in parallel and aggregate results'
}
}
```
**Completion Signal:** ✅ orchestrator-tool.workflow() spawns 3 tools, returns aggregated result
---
## Task 6.5: M6 Witness Test (VERIFICATION) 🔴
**Constraint:** M6 capabilities untested → Cannot verify orchestration works
**Witness Outcome:** All M6 witness acts pass programmatically
### Witness Acts
**Act 1: Tool Spawning**
```
Orchestrator spawns data-tool
Data-tool creates resource
Orchestrator receives success
```
**Act 2: Permission Inheritance**
```
Orchestrator at level 1
Orchestrator spawns data-tool with create-resource (requires level 2)
Operation DENIED (parent lacks permission)
Upgrade orchestrator to level 2
Orchestrator spawns data-tool with create-resource
Operation ALLOWED (inherited level 2)
```
**Act 3: Multi-Step Workflow**
```
Orchestrator.workflow()
→ data-tool.create-resource('x')
→ admin-tool.validate-resource('x')
→ data-tool.read-resource('x')
Returns aggregated result with all 3 steps
```
**Act 4: Recursion Depth Limit**
```
Tool-A spawns Tool-B (depth 1)
Tool-B spawns Tool-C (depth 2)
... continue to depth 6
Depth 6 spawn → ERROR (max depth 5)
```
**Act 5: Circular Dependency Detection**
```
Orchestrator spawns orchestrator (self-spawn)
ERROR: Circular dependency detected
```
**Act 6: Error Propagation**
```
Orchestrator.workflow()
→ data-tool.create-resource('x') ✅
→ admin-tool.delete-resource('x') ❌ (requires level 3, has level 2)
Workflow stops at step 2
Returns error with partial results
```
### Test Implementation
Create `test-m6-witness.mjs`:
```javascript
import { ConversationManager } from './dist/core/conversation-manager.js';
import { ConversationStore } from './dist/core/conversation-store.js';
const store = new ConversationStore({ dbPath: ':memory:' });
const manager = new ConversationManager(store);
await manager.waitForToolsLoaded();
console.log('=== M6 Witness Test ===\n');
// Act 1: Tool Spawning
console.log('Act 1: Tool Spawning');
const result1 = await manager.negotiate('m6-test', 'workflow', {});
console.assert(result1.success, 'Workflow should succeed');
console.assert(result1.output.steps === 3, 'Should execute 3 steps');
console.log('✅ PASSED\n');
// Act 2: Permission Inheritance
console.log('Act 2: Permission Inheritance');
// ... test implementation
console.log('✅ PASSED\n');
// ... Acts 3-6
```
**Completion Signal:** ✅ All 6 acts pass programmatically
---
## Task 6.6: Conversation State Tracking (OBSERVABILITY) 🔴
**Constraint:** Tool spawning invisible to user → Cannot see orchestration hierarchy
**Witness Outcome:** `conversation:status` shows tool hierarchy and delegation chain
### Acceptance Criteria
- [ ] Conversation state tracks parent-child relationships
- [ ] `conversation:status` shows tool hierarchy tree
- [ ] Shows which tools spawned which tools
- [ ] Shows permission delegation chain
- [ ] Shows current recursion depth
### Implementation
**Extend ConversationState:**
```typescript
interface ToolSpawnEvent {
parentTool: string;
childTool: string;
action: string;
depth: number;
timestamp: number;
permissionInherited: number;
}
interface ConversationState {
// ... existing fields
toolSpawns?: ToolSpawnEvent[];
}
```
**Update conversation:status:**
```typescript
private async handleConversationStatus(conversationId: string): Promise<NegotiationResult> {
const state = conversation.getState();
// Build tool hierarchy
const hierarchy = this.buildToolHierarchy(state.toolSpawns || []);
return {
success: true,
output: {
// ... existing fields
toolHierarchy: hierarchy,
maxDepth: Math.max(...(state.toolSpawns || []).map(s => s.depth)),
delegationChain: this.buildDelegationChain(state.permissionDelegations || [])
}
};
}
private buildToolHierarchy(spawns: ToolSpawnEvent[]): any {
// Build tree from spawn events
const roots = spawns.filter(s => !s.parentTool);
// ... recursive tree building
}
```
**Completion Signal:** ✅ `conversation:status` shows "orchestrator-tool → data-tool (depth 1)"
---
## M6 Completion Criteria
**M6 is complete when:**
1. ✅ Tools can spawn other tools via ToolContext
2. ✅ Permission inheritance flows from parent to child
3. ✅ Recursion depth limited to prevent stack overflow
4. ✅ Circular dependencies detected and blocked
5. ✅ Orchestrator tool demonstrates multi-step workflows
6. ✅ All 6 witness acts pass programmatically
7. ✅ Tool hierarchy visible in conversation:status
8. ✅ Error propagation from child to parent works
9. ✅ Parallel tool spawning supported (aggregate action)
10. ✅ Documentation updated with M6 examples
---
*"Tools don't orchestrate because we add orchestration code. Tools orchestrate because we remove the constraint preventing them from spawning tools."* — M6 Architecture Shift