Add nu_service.nu, .claude/, CLAUDE.md, hero_do_hero_livekit Rhai binary #12

Closed
opened 2026-04-19 21:17:51 +00:00 by mahmoud · 5 comments
Owner

Context

Repo is missing four standard Hero artifacts:

  1. scripts/nu_service.nu — install/start/stop/status lifecycle module delegating to hero_proc (nu_service).
  2. .claude/ — repo-local skills index + settings (synced from hero_skills).
  3. CLAUDE.md — repo-specific context file.
  4. hero_do_hero_livekit — Rhai scripting binary + feature flag + example .rhai scripts (rhai_bindings_generate_fix).

Goals

  • Add scripts/nu_service.nu following the service_proxy.nu pattern; expose install, start, stop, status subcommands.
  • Initialize .claude/ with a curated subset of skills relevant to this repo (see hero_skills/.claude/).
  • Write a concise CLAUDE.md covering architecture, sockets, how to build/run/test, and pointers to relevant skills.
  • Add a crates/hero_livekit_cli_rhai/ (or appropriate location) binary hero_do_hero_livekit that exposes SDK methods to Rhai; add per-crate Makefile and at least one example script under examples/*.rhai.

Related skills: nu_service, rhai_bindings_generate_fix, rhai_bindings_reference.

## Context Repo is missing four standard Hero artifacts: 1. `scripts/nu_service.nu` — install/start/stop/status lifecycle module delegating to hero_proc (`nu_service`). 2. `.claude/` — repo-local skills index + settings (synced from `hero_skills`). 3. `CLAUDE.md` — repo-specific context file. 4. `hero_do_hero_livekit` — Rhai scripting binary + feature flag + example `.rhai` scripts (`rhai_bindings_generate_fix`). ## Goals - Add `scripts/nu_service.nu` following the `service_proxy.nu` pattern; expose `install`, `start`, `stop`, `status` subcommands. - Initialize `.claude/` with a curated subset of skills relevant to this repo (see `hero_skills/.claude/`). - Write a concise `CLAUDE.md` covering architecture, sockets, how to build/run/test, and pointers to relevant skills. - Add a `crates/hero_livekit_cli_rhai/` (or appropriate location) binary `hero_do_hero_livekit` that exposes SDK methods to Rhai; add per-crate Makefile and at least one example script under `examples/*.rhai`. Related skills: `nu_service`, `rhai_bindings_generate_fix`, `rhai_bindings_reference`.
Author
Owner

no need .claude/ and CLAUDE.md

no need .claude/ and CLAUDE.md
Member

Implementation Spec for Issue #12 — nu_service.nu + hero_do_hero_livekit

Objective

Add two scripting/lifecycle artefacts to hero_livekit: a Nushell service module (scripts/nu_service.nu) that gives the repo a standard install/start/stop/status surface talking to hero_proc, and a new workspace crate hero_livekit_rhai producing a hero_do_hero_livekit binary that exposes the full LiveKitService OpenRPC surface to Rhai scripts. Both follow the nu_service and rhai_bindings_generate_fix + rhai_bindings_cmd_path skill conventions already used across the Hero ecosystem. Nothing in the .claude/ or root CLAUDE.md space is touched (dropped per maintainer comment).

Requirements

  • scripts/nu_service.nu matching the nu_service skill: two-action (hero_livekit_server + hero_livekit_ui) pattern, uses proc.nu + services/lib.nu, socket bases $"($sock_base)/hero_livekit/{rpc,ui}.sock", subcommands install/start/stop/status with --root/--reset flags.
  • Service metadata: context_name: "core", class: "system", critical: false. Binaries: hero_livekit_server hero_livekit_ui lk-backend (lk-backend is installed but is a supervised child of hero_livekit_server, not a hero_proc action).
  • New workspace member crate crates/hero_livekit_rhai producing binary hero_do_hero_livekit (via [[bin]] with required-features = ["rhai"]), a library holding the binding registration, plus ≥5 example .rhai scripts.
  • The Rhai binary injects SCRIPT_DIR, SCRIPT_FILE, and ARGS into the Rhai scope per the rhai_bindings_cmd_path skill.
  • Rhai engine exposes every method from crates/hero_livekit_server/src/livekit/core/openrpc.json (12 LiveKitService methods) plus a livekit_client(socket_path) constructor with a no-arg overload, using manual register_fn/register_type_with_name/register_get only.
  • Per-crate Makefile with build, build-do, install, installdev, check, clippy, test, run-examples, example NAME=….
  • Workspace root Cargo.toml adds crates/hero_livekit_rhai to [workspace] members.
  • Root Makefile gets passthrough targets (build-rhai, install-rhai, run-rhai-example).
  • README.md gains "Scripting" and "Service lifecycle via hero_proc" sections.

Files to Modify/Create

Path Purpose New/Modify
scripts/nu_service.nu Nu module: install/start/stop/status against hero_proc new
Cargo.toml (workspace) Add crates/hero_livekit_rhai to [workspace.members] modify
crates/hero_livekit_rhai/Cargo.toml Library + [[bin]] hero_do_hero_livekit, rhai feature gate new
crates/hero_livekit_rhai/src/lib.rs Public create_engine() + register() wiring new
crates/hero_livekit_rhai/src/client.rs Blocking wrapper around generated LiveKitClient (owns tokio runtime) new
crates/hero_livekit_rhai/src/bindings.rs Manual register_fn/register_get calls new
crates/hero_livekit_rhai/src/main.rs Binary entry: arg parsing + script runner + SCRIPT_DIR/FILE/ARGS scope injection new
crates/hero_livekit_rhai/examples/rhai/01_status.rhai Show service status new
crates/hero_livekit_rhai/examples/rhai/02_list_rooms.rhai Connect + list rooms new
crates/hero_livekit_rhai/examples/rhai/03_create_delete_room.rhai Create + verify + delete a room new
crates/hero_livekit_rhai/examples/rhai/04_issue_token.rhai Issue JWT + print grants new
crates/hero_livekit_rhai/examples/rhai/05_full_lifecycle.rhai install → configure → start → create → token → participants → stop new
crates/hero_livekit_rhai/Makefile Per-crate Rhai Makefile new
crates/hero_livekit_rhai/buildenv.sh PROJECT_NAME=hero_livekit_rhai, BINARIES=hero_do_hero_livekit, ALL_FEATURES=rhai new
Makefile (root) Add build-rhai/install-rhai/run-rhai-example passthrough targets modify
README.md Add "Scripting" + "Service lifecycle via hero_proc" sections modify

Implementation Plan

Step 1: scripts/nu_service.nu

Files: scripts/nu_service.nu (new)

Actions:

  • Follow the two-action nu_service skill template verbatim.
  • SVX_SERVICE_NAME = "hero_livekit", SVX_FORGE_LOC = "lhumina_code/hero_livekit".
  • SVX_BINARIES = ["hero_livekit_server" "hero_livekit_ui" "lk-backend"].
  • SVX_ACTIONS = ["hero_livekit_server" "hero_livekit_ui"] (intentionally omits lk-backend — supervised by the server).
  • Server socket: $"($sock_base)/hero_livekit/rpc.sock". UI socket: $"($sock_base)/hero_livekit/ui.sock".
  • UI health params: start_period_ms: 5000, interval_ms: 3000.
  • Service description: "hero_livekit — LiveKit SFU orchestrator for the Hero OS Suite."
  • context_name: "core", status: "start", critical: false, class: "system".
  • env: {RUST_LOG: "info"} — no custom HERO_LIVEKIT_* env vars need forwarding.
  • Subcommands: install, start, stop, status — delegate to svc_cargo_install, svx_drop_registration, proc action/service set/start/status helpers from the skill template.

Dependencies: none. Can run in parallel with: Steps 2–5.

Step 2: New crate crates/hero_livekit_rhai

Files: crates/hero_livekit_rhai/{Cargo.toml,src/lib.rs,src/client.rs,src/bindings.rs,src/main.rs,buildenv.sh} (all new); workspace Cargo.toml (modify to add member).

Cargo.toml (new crate):

[package]
name = "hero_livekit_rhai"
version.workspace = true
edition.workspace = true
description = "Rhai scripting bindings for hero_livekit"
license = "Apache-2.0"

[features]
default = ["rhai"]
rhai = ["dep:rhai"]

[dependencies]
hero_rpc_derive  = { workspace = true }
hero_rpc_openrpc = { workspace = true }
tokio            = { workspace = true }
serde            = { workspace = true }
serde_json       = { workspace = true }
anyhow           = { workspace = true }
thiserror        = { workspace = true }
dirs             = "6"
rhai             = { version = "1", features = ["sync"], optional = true }

[lib]
name = "hero_livekit_rhai"
path = "src/lib.rs"

[[bin]]
name = "hero_do_hero_livekit"
path = "src/main.rs"
required-features = ["rhai"]

src/client.rs — reuse the generated client via openrpc_client!, wrap it with a tokio runtime so Rhai (sync) can call blocking methods:

use hero_rpc_derive::openrpc_client;
openrpc_client!(
    "../hero_livekit_server/src/livekit/core/openrpc.json",
    name = "LiveKitClient"
);

pub struct LiveKitRhaiClient {
    inner: LiveKitClient,
    rt:    std::sync::Arc<tokio::runtime::Runtime>,
}

impl LiveKitRhaiClient {
    pub fn connect(socket_path: &str) -> anyhow::Result<Self> {
        let rt = tokio::runtime::Builder::new_multi_thread().enable_all().build()?;
        let inner = rt.block_on(LiveKitClient::connect_socket(socket_path))?;
        Ok(Self { inner, rt: std::sync::Arc::new(rt) })
    }
    pub fn rt(&self) -> &tokio::runtime::Runtime { &self.rt }
    pub fn inner(&self) -> &LiveKitClient { &self.inner }
}

pub fn default_socket_path() -> String {
    let base = std::env::var("HERO_SOCKET_DIR").unwrap_or_else(|_| {
        let home = std::env::var("HOME").expect("HOME must be set");
        format!("{}/hero/var/sockets", home)
    });
    format!("{}/hero_livekit/rpc.sock", base)
}

src/bindings.rs — manual Rhai registration. Constructors:

  • livekit_client() → default socket path
  • livekit_client(path: &str) → explicit socket path

Lifecycle methods (return String for ServiceState, lower-cased):

  • install(livekit_version: String, backend_version: String) -> String
  • configure(node_ip, api_key, api_secret, domain, livekit_port: i64, backend_port: i64, redis_address) -> String
  • start() -> String, stop() -> String, restart() -> String, status() -> String

Room methods:

  • create_room(name, max_participants: i64, empty_timeout: i64, metadata) -> Room
  • list_rooms() -> rhai::Array (Dynamic::from(Room) elements)
  • delete_room(name) -> bool

Participant methods:

  • list_participants(room) -> rhai::Array
  • remove_participant(room, identity) -> bool

Tokens:

  • issue_token(identity, room, ttl_secs: i64, can_publish: bool, can_subscribe: bool) -> AccessToken

Registered types via register_type_with_name + getters + to_string/to_debug:

  • Roomsid, name, num_participants, max_participants, empty_timeout, creation_time, metadata, status
  • Participantsid, identity, name, room_sid, state, joined_at, metadata
  • AccessTokensid, identity, room, issued_at, expires_at, grants

Every fallible call uses e.to_string().into() to produce Box<EvalAltResult>.

src/lib.rs:

pub mod client;
pub mod bindings;

pub use client::{LiveKitRhaiClient, default_socket_path};

#[cfg(feature = "rhai")]
pub fn register(engine: &mut rhai::Engine) { bindings::register(engine); }

#[cfg(feature = "rhai")]
pub fn create_engine() -> rhai::Engine {
    let mut engine = rhai::Engine::new();
    register(&mut engine);
    engine
}

src/main.rs follows the hero_do_* shape: arg dispatch for <script.rhai> [args...] / <directory> / -i stdin / --run <name> / --version / --help. Injects SCRIPT_DIR, SCRIPT_FILE, ARGS into the Rhai scope per rhai_bindings_cmd_path. Built-in scripts via include_str!("../examples/rhai/*.rhai").

buildenv.sh:

export PROJECT_NAME="hero_livekit_rhai"
export BINARIES="hero_do_hero_livekit"
export ALL_FEATURES="rhai"
export VERSION="0.1.0"
export PATCHLEVEL="patch"

Workspace Cargo.toml: append "crates/hero_livekit_rhai" to members.

Dependencies: none. Must precede: Steps 3 & 4. Can run in parallel with: Step 1.

Step 3: Example Rhai scripts

Files: crates/hero_livekit_rhai/examples/rhai/0{1..5}_*.rhai

Each script begins with #!/usr/bin/env hero_do_hero_livekit. Short and direct (no try/catch, no decorative comments per rhai_check):

  • 01_status.rhailet c = livekit_client(); print(c.status());
  • 02_list_rooms.rhai → iterate c.list_rooms() and print each room's name + participant count
  • 03_create_delete_room.rhai → create rhai-demo, print sid, delete, print result
  • 04_issue_token.rhai → issue a token for alice in room demo, print grants
  • 05_full_lifecycle.rhai → consume versions from ARGS, run installconfigurestart → create room → issue token → list participants → stop

Dependencies: Step 2. Can run in parallel with: Step 1, 4, 5.

Step 4: Per-crate Makefile + root passthrough

Files: crates/hero_livekit_rhai/Makefile (new), Makefile (root, modify)

Per-crate Makefile clones hero_books_lib_rhai/Makefile shape:

  • NAME := hero_livekit_rhai, DO := hero_do_hero_livekit
  • Targets: build, build-do, build-release, install, installdev, check, clippy, test, run-examples, example NAME=<n>
  • install copies ../../target/release/hero_do_hero_livekit to $(HOME)/hero/bin/

Root Makefile additions (near end, before clean):

build-rhai:
	$(MAKE) -C crates/hero_livekit_rhai build

install-rhai:
	$(MAKE) -C crates/hero_livekit_rhai install

run-rhai-example:
	$(MAKE) -C crates/hero_livekit_rhai example NAME=$(NAME)

Add them to .PHONY.

Dependencies: Step 2. Can run in parallel with: Step 1, 3, 5.

Step 5: README.md update

Files: README.md (modify)

Append two sections after "Documentation":

  • Service lifecycle via hero_proc — shows use scripts/nu_service.nu + nu_service install/start/status/stop with --root example.
  • Scripting (Rhai) — shows make install-rhai + hero_do_hero_livekit examples/rhai/01_status.rhai, points to crates/hero_livekit_rhai/examples/rhai/.

Dependencies: Steps 1 & 2 (for link accuracy). Can run in parallel with: Step 3, 4.

Acceptance Criteria

  • cargo build -p hero_livekit_rhai succeeds.
  • cargo build -p hero_livekit_rhai --bin hero_do_hero_livekit produces target/debug/hero_do_hero_livekit.
  • make install-rhai installs hero_do_hero_livekit into ~/hero/bin/.
  • hero_do_hero_livekit --help prints the usage banner.
  • With hero_livekit_server running, hero_do_hero_livekit crates/hero_livekit_rhai/examples/rhai/01_status.rhai prints the state.
  • hero_do_hero_livekit crates/hero_livekit_rhai/examples/rhai/02_list_rooms.rhai connects and enumerates.
  • use scripts/nu_service.nu; nu_service install builds/installs the workspace binaries.
  • nu_service start registers both actions + service and starts them; nu_service status shows running.
  • nu_service stop tears down registrations cleanly.
  • README.md gains the two new sections.
  • No try/catch, no decorative comments in the .rhai scripts (rhai_check compliant).

Notes

  • Socket path: binary defaults to $HERO_SOCKET_DIR/hero_livekit/rpc.sock cascading to ~/hero/var/sockets/hero_livekit/rpc.sock — consistent with the recent PR #16 (issue #13) wiring.
  • lk-backend: in BINARIES so install copies it, but NOT a hero_proc action (supervised by hero_livekit_server).
  • Feature flag default: default = ["rhai"] matches hero_books_lib_rhai ergonomics; --no-default-features still builds the library.
  • Why a separate crate: isolates Rhai dep from the server daemon; mirrors ecosystem pattern (hero_books_lib_rhai).
  • OpenRPC surface: we bind only the 12 LiveKitService.* methods currently exposed. Per-entity CRUD (room.set/get/delete/etc.) is NOT in the generated client today, so not bound here. If added later it regenerates automatically.
  • Prerequisite tooling for nu_service: nu shell in PATH, hero_proc running under the invoking user (or root with --root), hero_skills/tools/modules/ exported via NU_LIB_DIRS.
  • Rhai crate version: rhai = "1" with features = ["sync"] — matches ecosystem convention.
## Implementation Spec for Issue #12 — nu_service.nu + hero_do_hero_livekit ### Objective Add two scripting/lifecycle artefacts to `hero_livekit`: a Nushell service module (`scripts/nu_service.nu`) that gives the repo a standard `install`/`start`/`stop`/`status` surface talking to `hero_proc`, and a new workspace crate `hero_livekit_rhai` producing a `hero_do_hero_livekit` binary that exposes the full `LiveKitService` OpenRPC surface to Rhai scripts. Both follow the `nu_service` and `rhai_bindings_generate_fix` + `rhai_bindings_cmd_path` skill conventions already used across the Hero ecosystem. Nothing in the `.claude/` or root `CLAUDE.md` space is touched (dropped per maintainer comment). ### Requirements - `scripts/nu_service.nu` matching the `nu_service` skill: two-action (`hero_livekit_server` + `hero_livekit_ui`) pattern, uses `proc.nu` + `services/lib.nu`, socket bases `$"($sock_base)/hero_livekit/{rpc,ui}.sock"`, subcommands `install`/`start`/`stop`/`status` with `--root`/`--reset` flags. - Service metadata: `context_name: "core"`, `class: "system"`, `critical: false`. Binaries: `hero_livekit_server hero_livekit_ui lk-backend` (`lk-backend` is installed but is a supervised child of `hero_livekit_server`, not a hero_proc action). - New workspace member crate `crates/hero_livekit_rhai` producing binary `hero_do_hero_livekit` (via `[[bin]]` with `required-features = ["rhai"]`), a library holding the binding registration, plus ≥5 example `.rhai` scripts. - The Rhai binary injects `SCRIPT_DIR`, `SCRIPT_FILE`, and `ARGS` into the Rhai scope per the `rhai_bindings_cmd_path` skill. - Rhai engine exposes every method from `crates/hero_livekit_server/src/livekit/core/openrpc.json` (12 `LiveKitService` methods) plus a `livekit_client(socket_path)` constructor with a no-arg overload, using manual `register_fn`/`register_type_with_name`/`register_get` only. - Per-crate `Makefile` with `build`, `build-do`, `install`, `installdev`, `check`, `clippy`, `test`, `run-examples`, `example NAME=…`. - Workspace root `Cargo.toml` adds `crates/hero_livekit_rhai` to `[workspace] members`. - Root `Makefile` gets passthrough targets (`build-rhai`, `install-rhai`, `run-rhai-example`). - README.md gains "Scripting" and "Service lifecycle via hero_proc" sections. ### Files to Modify/Create | Path | Purpose | New/Modify | |---|---|---| | `scripts/nu_service.nu` | Nu module: install/start/stop/status against hero_proc | new | | `Cargo.toml` (workspace) | Add `crates/hero_livekit_rhai` to `[workspace.members]` | modify | | `crates/hero_livekit_rhai/Cargo.toml` | Library + `[[bin]] hero_do_hero_livekit`, `rhai` feature gate | new | | `crates/hero_livekit_rhai/src/lib.rs` | Public `create_engine()` + `register()` wiring | new | | `crates/hero_livekit_rhai/src/client.rs` | Blocking wrapper around generated `LiveKitClient` (owns tokio runtime) | new | | `crates/hero_livekit_rhai/src/bindings.rs` | Manual `register_fn`/`register_get` calls | new | | `crates/hero_livekit_rhai/src/main.rs` | Binary entry: arg parsing + script runner + SCRIPT_DIR/FILE/ARGS scope injection | new | | `crates/hero_livekit_rhai/examples/rhai/01_status.rhai` | Show service status | new | | `crates/hero_livekit_rhai/examples/rhai/02_list_rooms.rhai` | Connect + list rooms | new | | `crates/hero_livekit_rhai/examples/rhai/03_create_delete_room.rhai` | Create + verify + delete a room | new | | `crates/hero_livekit_rhai/examples/rhai/04_issue_token.rhai` | Issue JWT + print grants | new | | `crates/hero_livekit_rhai/examples/rhai/05_full_lifecycle.rhai` | install → configure → start → create → token → participants → stop | new | | `crates/hero_livekit_rhai/Makefile` | Per-crate Rhai Makefile | new | | `crates/hero_livekit_rhai/buildenv.sh` | `PROJECT_NAME=hero_livekit_rhai`, `BINARIES=hero_do_hero_livekit`, `ALL_FEATURES=rhai` | new | | `Makefile` (root) | Add `build-rhai`/`install-rhai`/`run-rhai-example` passthrough targets | modify | | `README.md` | Add "Scripting" + "Service lifecycle via hero_proc" sections | modify | ### Implementation Plan #### Step 1: scripts/nu_service.nu Files: `scripts/nu_service.nu` (new) Actions: - Follow the two-action nu_service skill template verbatim. - `SVX_SERVICE_NAME = "hero_livekit"`, `SVX_FORGE_LOC = "lhumina_code/hero_livekit"`. - `SVX_BINARIES = ["hero_livekit_server" "hero_livekit_ui" "lk-backend"]`. - `SVX_ACTIONS = ["hero_livekit_server" "hero_livekit_ui"]` (intentionally omits `lk-backend` — supervised by the server). - Server socket: `$"($sock_base)/hero_livekit/rpc.sock"`. UI socket: `$"($sock_base)/hero_livekit/ui.sock"`. - UI health params: `start_period_ms: 5000`, `interval_ms: 3000`. - Service description: `"hero_livekit — LiveKit SFU orchestrator for the Hero OS Suite."` - `context_name: "core"`, `status: "start"`, `critical: false`, `class: "system"`. - `env: {RUST_LOG: "info"}` — no custom HERO_LIVEKIT_* env vars need forwarding. - Subcommands: `install`, `start`, `stop`, `status` — delegate to `svc_cargo_install`, `svx_drop_registration`, `proc action/service set/start/status` helpers from the skill template. Dependencies: none. Can run in parallel with: Steps 2–5. #### Step 2: New crate crates/hero_livekit_rhai Files: `crates/hero_livekit_rhai/{Cargo.toml,src/lib.rs,src/client.rs,src/bindings.rs,src/main.rs,buildenv.sh}` (all new); workspace `Cargo.toml` (modify to add member). **Cargo.toml** (new crate): ```toml [package] name = "hero_livekit_rhai" version.workspace = true edition.workspace = true description = "Rhai scripting bindings for hero_livekit" license = "Apache-2.0" [features] default = ["rhai"] rhai = ["dep:rhai"] [dependencies] hero_rpc_derive = { workspace = true } hero_rpc_openrpc = { workspace = true } tokio = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } anyhow = { workspace = true } thiserror = { workspace = true } dirs = "6" rhai = { version = "1", features = ["sync"], optional = true } [lib] name = "hero_livekit_rhai" path = "src/lib.rs" [[bin]] name = "hero_do_hero_livekit" path = "src/main.rs" required-features = ["rhai"] ``` **src/client.rs** — reuse the generated client via `openrpc_client!`, wrap it with a tokio runtime so Rhai (sync) can call blocking methods: ```rust use hero_rpc_derive::openrpc_client; openrpc_client!( "../hero_livekit_server/src/livekit/core/openrpc.json", name = "LiveKitClient" ); pub struct LiveKitRhaiClient { inner: LiveKitClient, rt: std::sync::Arc<tokio::runtime::Runtime>, } impl LiveKitRhaiClient { pub fn connect(socket_path: &str) -> anyhow::Result<Self> { let rt = tokio::runtime::Builder::new_multi_thread().enable_all().build()?; let inner = rt.block_on(LiveKitClient::connect_socket(socket_path))?; Ok(Self { inner, rt: std::sync::Arc::new(rt) }) } pub fn rt(&self) -> &tokio::runtime::Runtime { &self.rt } pub fn inner(&self) -> &LiveKitClient { &self.inner } } pub fn default_socket_path() -> String { let base = std::env::var("HERO_SOCKET_DIR").unwrap_or_else(|_| { let home = std::env::var("HOME").expect("HOME must be set"); format!("{}/hero/var/sockets", home) }); format!("{}/hero_livekit/rpc.sock", base) } ``` **src/bindings.rs** — manual Rhai registration. Constructors: - `livekit_client()` → default socket path - `livekit_client(path: &str)` → explicit socket path Lifecycle methods (return `String` for ServiceState, lower-cased): - `install(livekit_version: String, backend_version: String) -> String` - `configure(node_ip, api_key, api_secret, domain, livekit_port: i64, backend_port: i64, redis_address) -> String` - `start() -> String`, `stop() -> String`, `restart() -> String`, `status() -> String` Room methods: - `create_room(name, max_participants: i64, empty_timeout: i64, metadata) -> Room` - `list_rooms() -> rhai::Array` (`Dynamic::from(Room)` elements) - `delete_room(name) -> bool` Participant methods: - `list_participants(room) -> rhai::Array` - `remove_participant(room, identity) -> bool` Tokens: - `issue_token(identity, room, ttl_secs: i64, can_publish: bool, can_subscribe: bool) -> AccessToken` Registered types via `register_type_with_name` + getters + `to_string`/`to_debug`: - `Room` — `sid`, `name`, `num_participants`, `max_participants`, `empty_timeout`, `creation_time`, `metadata`, `status` - `Participant` — `sid`, `identity`, `name`, `room_sid`, `state`, `joined_at`, `metadata` - `AccessToken` — `sid`, `identity`, `room`, `issued_at`, `expires_at`, `grants` Every fallible call uses `e.to_string().into()` to produce `Box<EvalAltResult>`. **src/lib.rs**: ```rust pub mod client; pub mod bindings; pub use client::{LiveKitRhaiClient, default_socket_path}; #[cfg(feature = "rhai")] pub fn register(engine: &mut rhai::Engine) { bindings::register(engine); } #[cfg(feature = "rhai")] pub fn create_engine() -> rhai::Engine { let mut engine = rhai::Engine::new(); register(&mut engine); engine } ``` **src/main.rs** follows the `hero_do_*` shape: arg dispatch for `<script.rhai> [args...]` / `<directory>` / `-i` stdin / `--run <name>` / `--version` / `--help`. Injects `SCRIPT_DIR`, `SCRIPT_FILE`, `ARGS` into the Rhai scope per `rhai_bindings_cmd_path`. Built-in scripts via `include_str!("../examples/rhai/*.rhai")`. **buildenv.sh**: ```bash export PROJECT_NAME="hero_livekit_rhai" export BINARIES="hero_do_hero_livekit" export ALL_FEATURES="rhai" export VERSION="0.1.0" export PATCHLEVEL="patch" ``` **Workspace Cargo.toml**: append `"crates/hero_livekit_rhai"` to `members`. Dependencies: none. Must precede: Steps 3 & 4. Can run in parallel with: Step 1. #### Step 3: Example Rhai scripts Files: `crates/hero_livekit_rhai/examples/rhai/0{1..5}_*.rhai` Each script begins with `#!/usr/bin/env hero_do_hero_livekit`. Short and direct (no try/catch, no decorative comments per `rhai_check`): - `01_status.rhai` → `let c = livekit_client(); print(c.status());` - `02_list_rooms.rhai` → iterate `c.list_rooms()` and print each room's name + participant count - `03_create_delete_room.rhai` → create `rhai-demo`, print sid, delete, print result - `04_issue_token.rhai` → issue a token for `alice` in room `demo`, print grants - `05_full_lifecycle.rhai` → consume versions from `ARGS`, run `install` → `configure` → `start` → create room → issue token → list participants → `stop` Dependencies: Step 2. Can run in parallel with: Step 1, 4, 5. #### Step 4: Per-crate Makefile + root passthrough Files: `crates/hero_livekit_rhai/Makefile` (new), `Makefile` (root, modify) Per-crate Makefile clones `hero_books_lib_rhai/Makefile` shape: - `NAME := hero_livekit_rhai`, `DO := hero_do_hero_livekit` - Targets: `build`, `build-do`, `build-release`, `install`, `installdev`, `check`, `clippy`, `test`, `run-examples`, `example NAME=<n>` - `install` copies `../../target/release/hero_do_hero_livekit` to `$(HOME)/hero/bin/` Root Makefile additions (near end, before `clean`): ```make build-rhai: $(MAKE) -C crates/hero_livekit_rhai build install-rhai: $(MAKE) -C crates/hero_livekit_rhai install run-rhai-example: $(MAKE) -C crates/hero_livekit_rhai example NAME=$(NAME) ``` Add them to `.PHONY`. Dependencies: Step 2. Can run in parallel with: Step 1, 3, 5. #### Step 5: README.md update Files: `README.md` (modify) Append two sections after "Documentation": - **Service lifecycle via hero_proc** — shows `use scripts/nu_service.nu` + `nu_service install/start/status/stop` with `--root` example. - **Scripting (Rhai)** — shows `make install-rhai` + `hero_do_hero_livekit examples/rhai/01_status.rhai`, points to `crates/hero_livekit_rhai/examples/rhai/`. Dependencies: Steps 1 & 2 (for link accuracy). Can run in parallel with: Step 3, 4. ### Acceptance Criteria - [ ] `cargo build -p hero_livekit_rhai` succeeds. - [ ] `cargo build -p hero_livekit_rhai --bin hero_do_hero_livekit` produces `target/debug/hero_do_hero_livekit`. - [ ] `make install-rhai` installs `hero_do_hero_livekit` into `~/hero/bin/`. - [ ] `hero_do_hero_livekit --help` prints the usage banner. - [ ] With `hero_livekit_server` running, `hero_do_hero_livekit crates/hero_livekit_rhai/examples/rhai/01_status.rhai` prints the state. - [ ] `hero_do_hero_livekit crates/hero_livekit_rhai/examples/rhai/02_list_rooms.rhai` connects and enumerates. - [ ] `use scripts/nu_service.nu; nu_service install` builds/installs the workspace binaries. - [ ] `nu_service start` registers both actions + service and starts them; `nu_service status` shows running. - [ ] `nu_service stop` tears down registrations cleanly. - [ ] README.md gains the two new sections. - [ ] No `try/catch`, no decorative comments in the `.rhai` scripts (rhai_check compliant). ### Notes - **Socket path**: binary defaults to `$HERO_SOCKET_DIR/hero_livekit/rpc.sock` cascading to `~/hero/var/sockets/hero_livekit/rpc.sock` — consistent with the recent PR #16 (issue #13) wiring. - **lk-backend**: in `BINARIES` so `install` copies it, but NOT a hero_proc action (supervised by `hero_livekit_server`). - **Feature flag default**: `default = ["rhai"]` matches `hero_books_lib_rhai` ergonomics; `--no-default-features` still builds the library. - **Why a separate crate**: isolates Rhai dep from the server daemon; mirrors ecosystem pattern (`hero_books_lib_rhai`). - **OpenRPC surface**: we bind only the 12 `LiveKitService.*` methods currently exposed. Per-entity CRUD (room.set/get/delete/etc.) is NOT in the generated client today, so not bound here. If added later it regenerates automatically. - **Prerequisite tooling** for nu_service: `nu` shell in PATH, `hero_proc` running under the invoking user (or root with `--root`), `hero_skills/tools/modules/` exported via `NU_LIB_DIRS`. - **Rhai crate version**: `rhai = "1"` with `features = ["sync"]` — matches ecosystem convention.
Member

Test Results (Issue #12 implementation)

cargo check --workspace

  • Status: PASS

cargo test --workspace

  • Status: PASS
  • Totals: 8 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out
  • New in this issue: hero_livekit_rhai (lib) + hero_do_hero_livekit (bin) unit tests
    • hero_livekit_rhai lib unittests: 0 passed; 0 failed; 0 ignored
    • hero_do_hero_livekit bin unittests: 0 passed; 0 failed; 0 ignored
    • hero_livekit_rhai doctests: 0 passed; 0 failed; 0 ignored
  • Pre-existing suites (unchanged): hero_livekit_server lib+bin 4+4 passed; 3 doctests ignored.

Notes

  • nu_service.nu is validated functionally by invoking nu scripts/nu_service.nu status against a running hero_proc; that is a runtime smoke test not covered by cargo test.
  • hero_do_hero_livekit runtime validation requires hero_livekit_server on $HERO_SOCKET_DIR/hero_livekit/rpc.sock; not covered by cargo test.
## Test Results (Issue #12 implementation) ### `cargo check --workspace` - Status: PASS ### `cargo test --workspace` - Status: PASS - Totals: 8 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out - New in this issue: hero_livekit_rhai (lib) + hero_do_hero_livekit (bin) unit tests - `hero_livekit_rhai` lib unittests: 0 passed; 0 failed; 0 ignored - `hero_do_hero_livekit` bin unittests: 0 passed; 0 failed; 0 ignored - `hero_livekit_rhai` doctests: 0 passed; 0 failed; 0 ignored - Pre-existing suites (unchanged): `hero_livekit_server` lib+bin 4+4 passed; 3 doctests ignored. ### Notes - `nu_service.nu` is validated functionally by invoking `nu scripts/nu_service.nu status` against a running hero_proc; that is a runtime smoke test not covered by `cargo test`. - `hero_do_hero_livekit` runtime validation requires `hero_livekit_server` on `$HERO_SOCKET_DIR/hero_livekit/rpc.sock`; not covered by `cargo test`.
Member

Implementation Summary

All 5 spec steps applied on branch development_nu_service_rhai (branched from main). .claude/ and CLAUDE.md deliverables dropped per comment.

Changes

Nushell service module

  • scripts/nu_service.nu — two-action module (hero_livekit_server + hero_livekit_ui) delegating to hero_proc via the services/lib.nu helpers. Subcommands: install, start, stop, status with --root/--reset flags. lk-backend is in SVX_BINARIES (copied by install) but not an action (supervised child of the server).

New workspace crate crates/hero_livekit_rhai

  • Cargo.toml — library + [[bin]] hero_do_hero_livekit gated on required-features = ["rhai"]. rhai = { version = "1", features = ["sync"], optional = true }.
  • src/client.rs — blocking wrapper LiveKitRhaiClient owning a tokio Runtime + Arc<LiveKitClient>. default_socket_path() cascades $HERO_SOCKET_DIR~/hero/var/sockets/hero_livekit/rpc.sock.
  • src/bindings.rs — manual Rhai registration for every method in openrpc.json (install, configure, start, stop, restart, status, create_room, list_rooms, delete_room, list_participants, remove_participant, issue_token). Registers Room, Participant, AccessToken as Rhai custom types with getters + to_string/to_debug.
  • src/lib.rs — public register(&mut Engine) and create_engine() -> Engine.
  • src/main.rs — CLI entry. Arg dispatch for <script.rhai> [args...], <directory>, -i stdin, --run <name>, --version, --help. Injects SCRIPT_DIR, SCRIPT_FILE, ARGS into the Rhai scope per the rhai_bindings_cmd_path skill.
  • buildenv.shPROJECT_NAME/BINARIES/ALL_FEATURES/VERSION/PATCHLEVEL.

Workspace Cargo.toml

  • Appended "crates/hero_livekit_rhai" to [workspace] members.

Example Rhai scripts — crates/hero_livekit_rhai/examples/rhai/

  • 01_status.rhai — prints service state.
  • 02_list_rooms.rhai — enumerate rooms with participant counts.
  • 03_create_delete_room.rhai — create + delete round-trip.
  • 04_issue_token.rhai — issue a JWT + print grants.
  • 05_full_lifecycle.rhai — install → configure → start → create → token → participants → stop. Reads versions from ARGS.
  • All scripts are executable (shebang + chmod +x) and rhai_check-compliant (no try/catch, no decorative headers).

Makefiles

  • crates/hero_livekit_rhai/Makefilebuild, build-do, build-release, install, installdev, check, clippy, test, run-examples, example EXAMPLE=<file>.
  • Root Makefilebuild-rhai, install-rhai, run-rhai-example passthroughs; added to .PHONY.

README.md

  • New "Service lifecycle via hero_proc" section describing nu_service.nu.
  • New "Scripting (Rhai)" section describing hero_do_hero_livekit with make install-rhai and example invocations.

Build + Test Results

  • cargo check --workspace — PASS
  • cargo test --workspace — 8 passed, 0 failed, 3 ignored (pre-existing rustdoc examples)
  • New crate adds no unit tests — it is a thin binding/runner layer. Functional validation is via the bundled .rhai scripts against a live hero_livekit_server.

Runtime validation (out of scope for cargo test)

  • nu scripts/nu_service.nu status — requires a running hero_proc.
  • hero_do_hero_livekit examples/rhai/01_status.rhai — requires hero_livekit_server on $HERO_SOCKET_DIR/hero_livekit/rpc.sock.

Notes

  • Socket default honors HERO_SOCKET_DIR (same cascade as PR #16 / issue #13).
  • The openrpc_client! macro regenerates the typed LiveKitClient at build time; any future OpenRPC methods surface automatically, but Rhai bindings for new methods must be added manually.
## Implementation Summary All 5 spec steps applied on branch `development_nu_service_rhai` (branched from `main`). `.claude/` and `CLAUDE.md` deliverables dropped per comment. ### Changes **Nushell service module** - `scripts/nu_service.nu` — two-action module (`hero_livekit_server` + `hero_livekit_ui`) delegating to `hero_proc` via the `services/lib.nu` helpers. Subcommands: `install`, `start`, `stop`, `status` with `--root`/`--reset` flags. `lk-backend` is in `SVX_BINARIES` (copied by install) but not an action (supervised child of the server). **New workspace crate `crates/hero_livekit_rhai`** - `Cargo.toml` — library + `[[bin]] hero_do_hero_livekit` gated on `required-features = ["rhai"]`. `rhai = { version = "1", features = ["sync"], optional = true }`. - `src/client.rs` — blocking wrapper `LiveKitRhaiClient` owning a tokio `Runtime` + `Arc<LiveKitClient>`. `default_socket_path()` cascades `$HERO_SOCKET_DIR` → `~/hero/var/sockets/hero_livekit/rpc.sock`. - `src/bindings.rs` — manual Rhai registration for every method in `openrpc.json` (`install`, `configure`, `start`, `stop`, `restart`, `status`, `create_room`, `list_rooms`, `delete_room`, `list_participants`, `remove_participant`, `issue_token`). Registers `Room`, `Participant`, `AccessToken` as Rhai custom types with getters + `to_string`/`to_debug`. - `src/lib.rs` — public `register(&mut Engine)` and `create_engine() -> Engine`. - `src/main.rs` — CLI entry. Arg dispatch for `<script.rhai> [args...]`, `<directory>`, `-i` stdin, `--run <name>`, `--version`, `--help`. Injects `SCRIPT_DIR`, `SCRIPT_FILE`, `ARGS` into the Rhai scope per the `rhai_bindings_cmd_path` skill. - `buildenv.sh` — `PROJECT_NAME/BINARIES/ALL_FEATURES/VERSION/PATCHLEVEL`. **Workspace `Cargo.toml`** - Appended `"crates/hero_livekit_rhai"` to `[workspace] members`. **Example Rhai scripts — `crates/hero_livekit_rhai/examples/rhai/`** - `01_status.rhai` — prints service state. - `02_list_rooms.rhai` — enumerate rooms with participant counts. - `03_create_delete_room.rhai` — create + delete round-trip. - `04_issue_token.rhai` — issue a JWT + print grants. - `05_full_lifecycle.rhai` — install → configure → start → create → token → participants → stop. Reads versions from `ARGS`. - All scripts are executable (shebang + `chmod +x`) and `rhai_check`-compliant (no try/catch, no decorative headers). **Makefiles** - `crates/hero_livekit_rhai/Makefile` — `build`, `build-do`, `build-release`, `install`, `installdev`, `check`, `clippy`, `test`, `run-examples`, `example EXAMPLE=<file>`. - Root `Makefile` — `build-rhai`, `install-rhai`, `run-rhai-example` passthroughs; added to `.PHONY`. **README.md** - New "Service lifecycle via hero_proc" section describing `nu_service.nu`. - New "Scripting (Rhai)" section describing `hero_do_hero_livekit` with `make install-rhai` and example invocations. ### Build + Test Results - `cargo check --workspace` — PASS - `cargo test --workspace` — 8 passed, 0 failed, 3 ignored (pre-existing rustdoc examples) - New crate adds no unit tests — it is a thin binding/runner layer. Functional validation is via the bundled `.rhai` scripts against a live `hero_livekit_server`. ### Runtime validation (out of scope for cargo test) - `nu scripts/nu_service.nu status` — requires a running `hero_proc`. - `hero_do_hero_livekit examples/rhai/01_status.rhai` — requires `hero_livekit_server` on `$HERO_SOCKET_DIR/hero_livekit/rpc.sock`. ### Notes - Socket default honors `HERO_SOCKET_DIR` (same cascade as PR #16 / issue #13). - The `openrpc_client!` macro regenerates the typed `LiveKitClient` at build time; any future OpenRPC methods surface automatically, but Rhai bindings for new methods must be added manually.
Member

Pull request opened: #17

This PR implements the changes discussed in this issue.

Pull request opened: https://forge.ourworld.tf/lhumina_code/hero_livekit/pulls/17 This PR implements the changes discussed in this issue.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_livekit#12
No description provided.