Logo

TL;DR

Quick reference for Ninja service management.

What is Ninja?

Ninja manages services packaged as Shurikens — self-contained bundles with metadata, scripts, and configuration templates.

Quick Start

# Install Ninja
git clone https://github.com/tunafysh/ninja.git
cd ninja && cargo build --release
sudo cp target/release/shurikenctl /usr/local/bin/

# Install a service
shurikenctl install service.shuriken

# Configure and start
shurikenctl configure service-name
shurikenctl start service-name

Core Concepts

Shuriken = Service package containing:

  • Metadata (name, version, platform)
  • Management scripts (start/stop logic)
  • Configuration templates
  • Optional tools and hooks

States: Running | Idle

Directory Structure

~/.ninja/
├── shurikens/{name}/      # Installed services
│   ├── .ninja/
│   │   ├── manifest.toml  # Service definition
│   │   ├── options.toml   # User config
│   │   ├── config.tmpl    # Template
│   │   └── manage.ns      # Management script
│   └── [service files]
└── blacksmith/            # Built packages

Manifest Essentials

[shuriken]
name = "my-service"
id = "com.example.service"
version = "1.0.0"
type = "daemon"

[shuriken.management]
type = "script"
script-path = "manage.ns"

[config]
config-path = "server.conf"

[logs]
log-path = "logs/service.log"

Management Script

function start()
    local result = proc.spawn("bin/server")
    fs.write(".ninja/service.pid", tostring(result.pid))
end

function stop()
    local pid = fs.read(".ninja/service.pid")
    proc.kill_pid(tonumber(pid))
    fs.remove(".ninja/service.pid")
end

Configuration

Template (.ninja/config.tmpl):

[server]
host = {{ host }}
port = {{ port }}
root = {{ root }}

Options (.ninja/options.toml):

host = "localhost"
port = 8080

Generate:

shurikenctl configure service-name

Package Format

.shuriken binary structure:

[MAGIC: "HSRZEG"]
[metadata_length: u16]
[metadata: CBOR]
[archive_length: u32]
[archive: tar.gz]
[signature: SHA-256]

Common Commands

# List services
shurikenctl list

# Start/stop
shurikenctl start {name}
shurikenctl stop {name}

# Configure
shurikenctl configure {name}

# Build package
shurikenctl forge

# Run script
shurikenctl run script.ns

# Start API server
shurikenctl api --port 8080

Lua API Quick Reference

-- Filesystem
fs.read(path)
fs.write(path, content)
fs.exists(path)
fs.create_dir(path)

-- Process
proc.spawn(command)
proc.kill_pid(pid)

-- Shell
shell.exec(command)

-- Environment
env.os          -- "linux", "windows", "macos"
env.get(key)

-- Time
time.sleep(seconds)
time.now(format)

-- Logging
log.info(message)
log.error(message)

DSL Quick Reference

# Select and manage
select myapp
start
stop
configure

# Configuration
set port 8080
toggle debug
configure {
  host = "localhost"
  port = 8080
}

# Scripts
execute script.ns

HTTP API Endpoints

GET    /api/shurikens              # List all
GET    /api/shurikens/states       # Get states
POST   /api/shurikens/{name}/start # Start
POST   /api/shurikens/{name}/stop  # Stop

Platform Support

  • Linux: x86_64, aarch64
  • Windows: x86_64
  • macOS: x86_64, aarch64

Key Features

✓ Cross-platform service management
✓ Script-based or native binary control
✓ Template-based configuration
✓ PID + start time verification
✓ Lua scripting with system APIs
✓ HTTP API and DSL
✓ MCP tool integration

Best Practices

  1. Use script management (native is deprecated)
  2. Provide configuration defaults in options.toml
  3. Use {{ root }} for portable paths
  4. Version semantically (e.g., 1.0.0)
  5. Test locally before packaging

Troubleshooting

# Service won't start
cat ~/.ninja/shurikens/{name}/.ninja/shuriken.lck
tail -f ~/.ninja/shurikens/{name}/logs/service.log

# Stale lock file (CAREFUL!)
ps aux | grep {name}
shurikenctl lockpick {name}

# Configuration issues
shurikenctl configure {name}
cat ~/.ninja/shurikens/{name}/{config-path}

Learn More

Resources

On this page