# Zinit Rhai Scripting Guide
Zinit supports Rhai scripting for service automation. You can use Rhai scripts to programmatically manage services, automate deployment workflows, and orchestrate complex service dependencies.
## Quick Start
### 1. Using Shebang (Executable Scripts)
Create a script with the shebang header:
```bash
#!/usr/bin/env zinit
// Your Rhai script here
let factory = new ZinitFactory();
let z = factory.connect();
let services = z.list();
print("Services: " + services);
```
Make it executable and run it directly:
```bash
chmod +x script.rhai
./script.rhai
```
### 2. Using zinit Command
Run a single script:
```bash
zinit rhai script.rhai
```
Run all `.rhai` scripts in a directory (sorted alphabetically):
```bash
zinit rhai ./scripts/
```
This will execute all `.rhai` files in the directory in lexicographic order, useful for multi-step deployments.
## API Reference
### ZinitFactory
The factory creates connections to the zinit daemon.
```rhai
// Create a factory
let factory = new ZinitFactory();
// Configure and connect (fluent API)
let z = factory
.socket("/custom/path.sock") // Optional: custom socket path
.log_level(2) // Optional: 0-3 (Silent, Minimal, Normal, Verbose)
.connect(); // Connect to daemon
```
### ZinitHandle
Once connected, you have a handle with these methods:
#### Service Management
```rhai
// List all services
let services = z.list();
for name in services {
print(name);
}
// Get service status
let status = z.status("service-name");
print("State: " + status.state); // inactive, blocked, starting, running, stopping, exited, failed
print("PID: " + status.pid);
print("Uptime: " + status.uptime);
// Control services
z.start("service-name");
z.stop("service-name");
z.restart("service-name");
// Signal service
z.kill("service-name", "SIGTERM");
// Create/delete services
let config = new ServiceConfig();
config.name = "my-service";
config.exec = "/usr/bin/my-app";
z.service_set(config);
z.service_delete("my-service");
```
#### Information Queries
```rhai
// Show dependency tree
let tree = z.tree();
print(tree);
// Explain why service is blocked
let why = z.why("blocked-service");
print("Blocked by: " + why);
// Get logs
let logs = z.logs(Some("service-name"), Some(100));
for log in logs {
print(log);
}
// Get debug state
let debug = z.debug_state();
print(debug);
```
#### Xinet (Socket Activation)
```rhai
// Register proxy
let xinet_config = new XinetConfig();
xinet_config.name = "web-proxy";
xinet_config.listen = ["unix:/tmp/web.sock"];
xinet_config.backend = "tcp:127.0.0.1:8080";
xinet_config.service = "web-app";
z.xinet_set(xinet_config);
// Check proxy status
let status = z.xinet_status(Some("web-proxy"));
print("Proxy status: " + status);
// Delete proxy
z.xinet_delete("web-proxy");
```
## Examples
### Example 1: Simple Health Check
```bash
#!/usr/bin/env zinit
let z = new ZinitFactory().connect();
let services = z.list();
for service in services {
let status = z.status(service);
if status.state != "running" {
print("WARNING: " + service + " is not running!");
}
}
```
### Example 2: Deployment Pipeline
Scripts in a directory are executed in order (alphabetically sorted):
```
scripts/
01-backup.rhai # Backup current state
02-stop-services.rhai # Stop services
03-deploy.rhai # Deploy new code
04-start-services.rhai # Start services
05-verify.rhai # Verify deployment
```
Run with:
```bash
zinit rhai scripts/
```
### Example 3: Conditional Service Management
```bash
#!/usr/bin/env zinit
let z = new ZinitFactory().log_level(2).connect();
// Only start services if they're not already running
let services = z.list();
for service in services {
let status = z.status(service);
if status.state == "inactive" {
print("Starting " + service);
z.start(service);
}
}
```
### Example 4: Service Configuration Builder
```bash
#!/usr/bin/env zinit
let z = new ZinitFactory().connect();
// Create a new service
let config = new ServiceConfig();
config.name = "database";
config.exec = "/usr/bin/postgres -D /var/lib/postgres";
config.dir = "/var/lib/postgres";
config.restart = "on-failure";
config.restart_delay_ms = 5000;
z.service_set(config);
print("Created service: database");
// Verify
let status = z.status("database");
print("Service state: " + status.state);
```
## Features
- ✅ **Shebang Support**: Use `#!/usr/bin/env zinit` in scripts
- ✅ **Directory Execution**: Run all `.rhai` files in a directory, sorted
- ✅ **Shebang Stripping**: Shebang lines are automatically removed before execution
- ✅ **Error Handling**: Failed scripts report errors with file paths
- ✅ **Fluent API**: Chain method calls for configuration
- ✅ **Type Safety**: Full Rhai type system with zinit types
- ✅ **Logging Levels**: 4 levels of logging control (Silent to Verbose)
## Technical Details
### Script Execution Model
1. Scripts are loaded from file or directory
2. Shebang line (`#!/usr/bin/env zinit`) is stripped if present
3. Each script creates its own ZinitFactory and connects independently
4. Scripts are executed in alphabetical order when a directory is provided
5. Errors in one script stop execution of subsequent scripts
### Type System
All Rhai scripts use zinit SDK types:
- `State` - enum: Inactive, Blocked, Starting, Running, Stopping, Exited, Failed
- `Status` - enum: Start, Stop, Ignore
- `ServiceClass` - enum: User, System
- `RestartPolicy` - enum: Always, OnFailure, Never
- `ServiceConfig`, `ServiceDef`, `DependencyDef`, etc.
### Socket Configuration
By default, zinit looks for the socket at:
- Linux: `/run/zinit/zinit.sock`
- macOS/Darwin: `$HOME/.zinit/socket`
Override with `socket()` method on ZinitFactory.
## Troubleshooting
### Script won't execute as shebang
Ensure the file is executable:
```bash
chmod +x script.rhai
```
And the shebang line is exact:
```bash
#!/usr/bin/env zinit
```
### Connection fails
Check that:
1. zinit-server is running: `pgrep zinit-server`
2. Socket path is correct: `ls -la /run/zinit/socket`
3. User has permission to socket file
### Script errors
Use the verbose logging flag to debug:
```rhai
let z = new ZinitFactory()
.log_level(3) // Maximum verbosity
.connect();
```
## Performance
- Scripts that list all services: O(n) where n is number of services
- Status queries are fast (single RPC call)
- Log retrieval depends on log size
- Directory execution processes files sequentially