Documentation Index
Fetch the complete documentation index at: https://doc.ambientsoul.ai/llms.txt
Use this file to discover all available pages before exploring further.
Shell Development Guide
Learn how to create platform-specific shells that host Soul Kernel on new devices and platforms.
Overview
A Shell is a platform-specific application that:
- Embeds or connects to Soul Kernel
- Provides native UI/UX
- Manages platform resources
- Handles device capabilities
Architecture Patterns
1. Embedded Pattern (Mobile, Edge)
The kernel runs in-process with the shell:
┌─────────────────┐
│ Shell App │
│ ┌───────────┐ │
│ │Soul Kernel│ │
│ └───────────┘ │
└─────────────────┘
2. Service Pattern (Desktop, Server)
The kernel runs as a separate service:
┌─────────────┐ gRPC ┌──────────────┐
│ Shell UI │◄─────────────►│ Soul Service │
└─────────────┘ └──────────────┘
3. Distributed Pattern (Cloud, IoT)
Multiple shells connect to shared kernel:
┌────────┐ ┌────────┐ ┌────────┐
│Mobile │ │ Web │ │Physical│
└───┬────┘ └───┬────┘ └───┬────┘
└───────────┼───────────┘
▼
┌─────────────┐
│Soul Cluster │
└─────────────┘
Creating a New Shell
Step 1: Choose Integration Method
Option A: Native Binding (Rust FFI)
Best for: Mobile apps, embedded systems
// Create C bindings
#[no_mangle]
pub extern "C" fn soul_init() -> *mut SoulKernel {
Box::into_raw(Box::new(SoulKernel::new()))
}
#[no_mangle]
pub extern "C" fn soul_ask(
kernel: *mut SoulKernel,
query: *const c_char
) -> *mut c_char {
// Implementation
}
Option B: gRPC Client
Best for: Desktop apps, web services
// soul_service.proto
service SoulService {
rpc Initialize(InitRequest) returns (InitResponse);
rpc Ask(AskRequest) returns (AskResponse);
rpc Remember(RememberRequest) returns (RememberResponse);
rpc StreamEvents(EventRequest) returns (stream Event);
}
Option C: WebAssembly
Best for: Web browsers, sandboxed environments
// Compile with wasm-pack
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub struct WebSoul {
kernel: SoulKernel,
}
#[wasm_bindgen]
impl WebSoul {
pub fn new() -> Self {
Self { kernel: SoulKernel::new() }
}
pub fn ask(&mut self, query: &str) -> String {
self.kernel.ask(query)
}
}
Step 2: Implement Core Features
1. Initialization
// Example: React Native Shell
import { NativeModules } from 'react-native';
const { SoulBridge } = NativeModules;
export class Soul {
private initialized = false;
async initialize(config: SoulConfig) {
if (this.initialized) return;
await SoulBridge.initialize({
modelPath: config.modelPath,
memoryPath: config.memoryPath,
skills: config.enabledSkills,
});
this.initialized = true;
}
}
2. Communication
// Example: iOS Shell
class SoulManager: ObservableObject {
@Published var responses: [SoulResponse] = []
private let kernel: OpaquePointer
func ask(_ query: String) async throws -> String {
return try await withCheckedThrowingContinuation { continuation in
soul_ask_async(kernel, query) { response, error in
if let error = error {
continuation.resume(throwing: error)
} else {
continuation.resume(returning: response)
}
}
}
}
}
3. Memory Sync
// Example: Android Shell
class SoulSyncManager(context: Context) {
private val syncWorker = WorkManager.getInstance(context)
fun scheduleSync() {
val syncRequest = PeriodicWorkRequestBuilder<SoulSyncWorker>(
15, TimeUnit.MINUTES
).setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
).build()
syncWorker.enqueueUniquePeriodicWork(
"soul-sync",
ExistingPeriodicWorkPolicy.KEEP,
syncRequest
)
}
}
iOS Specific
// Handle background processing
class SoulBackgroundTask {
func scheduleAppRefresh() {
BGTaskScheduler.shared.register(
forTaskWithIdentifier: "io.soulkernel.sync",
using: nil
) { task in
self.handleBackgroundSync(task)
}
}
private func handleBackgroundSync(_ task: BGTask) {
Soul.shared.sync { success in
task.setTaskCompleted(success: success)
}
}
}
Android Specific
// Handle lifecycle
class SoulLifecycleObserver : DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) {
Soul.instance.resume()
}
override fun onStop(owner: LifecycleOwner) {
Soul.instance.pause()
}
}
Unity Specific
// Handle Unity lifecycle
public class SoulBehaviour : MonoBehaviour {
private SoulClient client;
void Awake() {
DontDestroyOnLoad(gameObject);
client = new SoulClient();
}
void OnApplicationPause(bool pauseStatus) {
if (pauseStatus) {
client.Pause();
} else {
client.Resume();
}
}
}
Step 4: UI/UX Guidelines
Conversation Interface
// Example: React component
function SoulChat() {
const [messages, setMessages] = useState([]);
const [input, setInput] = useState('');
const soul = useSoul();
const sendMessage = async () => {
const userMessage = { role: 'user', content: input };
setMessages([...messages, userMessage]);
const response = await soul.ask(input);
const soulMessage = { role: 'soul', content: response };
setMessages([...messages, userMessage, soulMessage]);
setInput('');
};
return (
<ChatContainer>
<MessageList messages={messages} />
<InputBar
value={input}
onChange={setInput}
onSubmit={sendMessage}
/>
</ChatContainer>
);
}
Status Indicators
// Show Soul state
enum SoulState {
case initializing
case ready
case thinking
case syncing
case error(String)
}
struct SoulStatusView: View {
@ObservedObject var soul: Soul
var body: some View {
HStack {
statusIcon
Text(statusText)
.foregroundColor(statusColor)
}
}
var statusIcon: some View {
switch soul.state {
case .thinking:
return ProgressView()
case .syncing:
return Image(systemName: "arrow.triangle.2.circlepath")
// ...
}
}
}
Testing Your Shell
Unit Tests
@Test
fun testSoulInitialization() {
val soul = Soul(mockContext)
soul.initialize()
assertTrue(soul.isReady)
assertNotNull(soul.version)
}
Integration Tests
func testSoulConversation() async throws {
let soul = try await Soul.test()
let response = try await soul.ask("Hello")
XCTAssertFalse(response.isEmpty)
XCTAssertTrue(response.contains("Hello"))
}
UI Tests
// Cypress example
describe('Soul Chat', () => {
it('responds to user input', () => {
cy.visit('/chat');
cy.get('[data-testid=chat-input]').type('Hello Soul');
cy.get('[data-testid=send-button]').click();
cy.get('[data-testid=message-list]')
.should('contain', 'Hello Soul')
.and('contain', 'Hello!');
});
});
1. Lazy Loading
// Load kernel only when needed
class LazyKernel {
private kernel?: SoulKernel;
async getKernel(): Promise<SoulKernel> {
if (!this.kernel) {
this.kernel = await import('./soul-kernel');
}
return this.kernel;
}
}
2. Response Caching
class CachedSoul {
private let cache = NSCache<NSString, SoulResponse>()
func ask(_ query: String) async -> String {
let key = query as NSString
if let cached = cache.object(forKey: key) {
return cached.text
}
let response = await soul.ask(query)
cache.setObject(response, forKey: key)
return response.text
}
}
3. Batch Operations
class BatchedSoul {
private val pendingQueries = mutableListOf<Query>()
fun askBatched(query: String): Deferred<String> {
val deferred = CompletableDeferred<String>()
pendingQueries.add(Query(query, deferred))
if (pendingQueries.size >= BATCH_SIZE) {
processBatch()
}
return deferred
}
}
Distribution
Mobile App Stores
# iOS App Store requirements
- Binary size < 200MB uncompressed
- Privacy manifest for AI features
- Age rating considerations
- Export compliance (encryption)
# Google Play requirements
- APK/AAB size limits
- Privacy policy URL
- Permissions justification
- Content rating
Desktop Distribution
# Example: Tauri config
[tauri]
bundle.identifier = "io.soulkernel.desktop"
bundle.icon = ["icons/icon.png"]
bundle.resources = ["models/*", "skills/*"]
[tauri.bundle.macos]
frameworks = ["SoulKernel.framework"]
Web Deployment
// Service worker for offline support
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open('soul-v1').then((cache) => {
return cache.addAll([
'/soul-kernel.wasm',
'/soul-kernel.js',
'/models/base.onnx',
]);
})
);
});
Troubleshooting
Common Issues
-
Kernel Won’t Initialize
- Check file paths
- Verify permissions
- Ensure sufficient memory
-
Slow Response Times
- Profile kernel calls
- Check network latency
- Optimize model size
-
Memory Leaks
- Use proper cleanup
- Monitor memory usage
- Test lifecycle events
# Enable verbose logging
export RUST_LOG=soul_kernel=debug
# Profile performance
cargo flamegraph --bin soul-shell
# Monitor memory
valgrind --leak-check=full ./soul-shell
Next Steps
- Study existing shells
- Read platform-specific tutorials:
- Join #shell-dev on Discord