The Orchestrator is Maurice's AI agent - a reactive physical intelligence that interacts with the world through robot operations and user-defined primitives. When users give natural language instructions, the Orchestrator intelligently selects and executes appropriate robot behaviors to accomplish the requested tasks.
The Orchestrator acts as a bridge between user intentions and robot actions by:
Understanding natural language requests
Selecting appropriate primitives for tasks
Coordinating physical and digital operations
Providing feedback about actions and outcomes
Extending with Directives
Builders can customize and extend the Orchestrator's capabilities through Directives. A Directive tells the Orchestrator:
Which primitives it can use
How to understand when and how to use them
Creating Directives
Basic Structure
A Directive consists of two key components:
from innate.directive import Directivefrom typing import ListclassBasicDirective(Directive):defget_primitives(self) -> List[str]:""" Define which primitives this directive can use Returns: List of primitive names """return ["primitive_one","primitive_two" ]defget_prompt(self) ->str:""" Define how to use the primitives Returns: String with usage instructions """return"""You are Maurice a smart robot. You have these primitives available:primitive_one:- Used for [purpose]- Parameters: [list parameters if any]- Use when [describe situations]primitive_two:- Used for [purpose]- Parameters: [list parameters if any]- Use when [describe situations]For each request:1. Choose the appropriate primitive2. Extract any needed parameters3. Execute the primitive4. Provide clear feedback"""
When creating a Directive:
Create a Python file in the ~/directives directory
Inherit from the Directive base class
Implement get_primitives() to list available primitives
Implement get_prompt() to define usage instructions
Using Directives
You can activate and deactivate directives in two ways:
Option 1: Command Line Interface
Use the Maurice SDK CLI commands:
# Activate a directiveinnatedirectiveactivatedirective_name# Deactivate all directivesinnatedirectivedeactivate
Option 2: Maurice App
Connect to your robot through the Maurice app
Navigate to the Directives page
Click your desired directive to activate it
Hit the cancel button to deactivate the current directive
When a directive is activated, the Orchestrator will use its configuration to understand and respond to user requests.
Examples
Maurice Security System
Here's a complete example showing how to build a simple security system using the Orchestrator:
1. Creating the Notify User Primitive
File: ~/primitives/notify_user.py
from innate.primitive import Primitivefrom typing import Tupleimport smtplibfrom email.message import EmailMessageclassNotifyUser(Primitive):def__init__(self):super().__init__()# Email configuration self.smtp_server ="smtp.gmail.com" self.smtp_port =587 self.sender_email ="maurice@example.com" self.user_email ="user@example.com" self.sender_password ="your-app-password"defguidelines(self) ->str:return""" Use this primitive to notify the user via email about important events or findings. Do not use for routine or non-critical notifications. """defexecute(self,description:str) -> Tuple[str,bool]:try: msg =EmailMessage() msg.set_content(description) msg['Subject']='Security Alert from Maurice' msg['From']= self.sender_email msg['To']= self.user_emailwith smtplib.SMTP(self.smtp_server, self.smtp_port)as server: server.starttls() server.login(self.sender_email, self.sender_password) server.send_message(msg)returnf"Notification sent: {description}",TrueexceptExceptionas e:returnf"Failed to send notification: {str(e)}",False
2. Creating the Patrol Primitive
File: ~/primitives/patrol.py
from innate.primitive import Primitivefrom innate import navigationfrom typing import Tupleimport timeclassPatrol(Primitive):def__init__(self):super().__init__() navigation.init() self.locations = ["kitchen","living_room","door"]defguidelines(self) ->str:return""" Use this primitive to perform a security patrol of the house. The robot will visit key locations in sequence. """defexecute(self) -> Tuple[str,bool]:try:for location in self.locations: navigation.go_to_memory(location) time.sleep(5) navigation.go_home()return"Patrol completed successfully",TrueexceptExceptionas e:returnf"Patrol interrupted: {str(e)}",Falsedefinterrupt(self): navigation.interrupt()
3. Creating the Security Directive
File: ~/directives/security_directive.py
from innate.directive import Directivefrom typing import ListclassSecurityDirective(Directive):defget_primitives(self) -> List[str]:return ["patrol","notify_user" ]defget_prompt(self) ->str:return"""You are Maurice's security system. You monitor the house and notify the owner of any issues.Available primitives:patrol:- Used to inspect key areas of the house- No parameters needed- Use when: - Asked to check the house - Regular security rounds are needed - Suspicious activity reportednotify_user:- Used to send important alerts to the owner- Parameters: description (string) - what to notify about- Use when: - Suspicious activity is detected - Important events need attention - After patrol if issues foundFor each request:1. If asked to check the house, use patrol2. If something suspicious is found, use notify_user3. Always explain what you're doing4. Maintain security awareness at all timesSafety is the top priority. If anything seems unsafe, notify the user immediately."""
Using the Security System
Place files in correct directories:
Put primitives in ~/primitives/
Put directive in ~/directives/
Activate the security directive using either:
innate directive activate security_directive
Or use the Maurice app:
Navigate to the Directives page
Click on "security_directive"
3. The robot can now handle commands like: - "Check the house" - "Do a security patrol" - "Alert me if anything seems wrong"
The Orchestrator will use the directive's prompt to understand these requests and execute the appropriate primitives in response.