From 8b0e74c4e9ea84dd4e855b86e56c12c30de0c63e Mon Sep 17 00:00:00 2001 From: MrBT-nano Date: Sun, 10 May 2026 20:01:28 +0700 Subject: [PATCH 1/6] chore: ignore .cargo/ directory to secure private registry configuration --- .gitignore | 1 + STRUCTURE.tree | 15 +++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index d0d7820..edaeb05 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ Thumbs.db .superpowers/ docs/ STRUCTURE.tree +.cargo/ diff --git a/STRUCTURE.tree b/STRUCTURE.tree index 73ad5cb..d2516bc 100644 --- a/STRUCTURE.tree +++ b/STRUCTURE.tree @@ -1,6 +1,8 @@ . ├── ARCHITECTURE.md ├── buf.yaml +├── .cargo +│   └── config.toml ├── Cargo.lock ├── Cargo.toml ├── CLAUDE.md @@ -26,9 +28,14 @@ ├── DEPLOYMENT_GUIDE.md ├── DESIGN_DECISIONS.md ├── docs -│   └── specs -│   └── ecosystem -│   └── 2026-05-01-canonical-proto-standard.md +│   ├── specs +│   │   └── ecosystem +│   │   └── 2026-05-01-canonical-proto-standard.md +│   └── superpowers +│   ├── plans +│   │   └── 2026-05-01-private-registry-integration.md +│   └── specs +│   └── 2026-05-01-private-registry-integration.md ├── FAQ.md ├── GEMINI.md ├── .github @@ -71,4 +78,4 @@ ├── TROUBLESHOOTING.md └── VISION.md -23 directories, 49 files +27 directories, 52 files From 7c17434c8aa571b58e536b20316a99d315f0d3f1 Mon Sep 17 00:00:00 2001 From: MrBT-nano Date: Sun, 10 May 2026 20:03:03 +0700 Subject: [PATCH 2/6] chore: configure vtuber-registry connection --- .cargo/config.toml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .cargo/config.toml diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..425b62c --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[registries.vtuber-registry] +index = "sparse+http://kellnr.cntm.labs:31500/api/v1/crates/" From 9234e2bcf4ecc87a9a6dcb4856e18b8e291eadf9 Mon Sep 17 00:00:00 2001 From: MrBT-nano Date: Sun, 10 May 2026 20:08:55 +0700 Subject: [PATCH 3/6] feat: add vtuber-contracts dependency from private registry --- .cargo/config.toml | 2 -- Cargo.lock | 13 +++++++++++++ Cargo.toml | 1 + crates/brain-proto/Cargo.toml | 1 + 4 files changed, 15 insertions(+), 2 deletions(-) delete mode 100644 .cargo/config.toml diff --git a/.cargo/config.toml b/.cargo/config.toml deleted file mode 100644 index 425b62c..0000000 --- a/.cargo/config.toml +++ /dev/null @@ -1,2 +0,0 @@ -[registries.vtuber-registry] -index = "sparse+http://kellnr.cntm.labs:31500/api/v1/crates/" diff --git a/Cargo.lock b/Cargo.lock index e0b6ba1..dc735e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -142,6 +142,7 @@ dependencies = [ "prost", "tonic", "tonic-build", + "vtuber-contracts", ] [[package]] @@ -1092,6 +1093,18 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "vtuber-contracts" +version = "0.1.0" +source = "sparse+http://kellnr.cntm.labs:31500/api/v1/crates/" +checksum = "7f8f2c502447e2385948167ca8a2b1f0815a85798ffc3a958ae9afa703bb0464" +dependencies = [ + "prost", + "prost-types", + "tonic", + "tonic-build", +] + [[package]] name = "want" version = "0.3.1" diff --git a/Cargo.toml b/Cargo.toml index b979a6c..a911d92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,3 +16,4 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" tracing = "0.1" tracing-subscriber = "0.3" +vtuber-contracts = { version = "0.1.0", registry = "vtuber-registry" } diff --git a/crates/brain-proto/Cargo.toml b/crates/brain-proto/Cargo.toml index f318092..8b64afa 100644 --- a/crates/brain-proto/Cargo.toml +++ b/crates/brain-proto/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] tonic = { workspace = true } prost = { workspace = true } +vtuber-contracts = { workspace = true } [build-dependencies] tonic-build = "0.12" From 0f7d641ec9f0cca4ececa380a94812f3a2188b48 Mon Sep 17 00:00:00 2001 From: MrBT-nano Date: Sun, 10 May 2026 20:40:56 +0700 Subject: [PATCH 4/6] feat: integrate and use vtuber-contracts and vtuber-commons --- Cargo.lock | 124 +++++++++++++++++++++++++ Cargo.toml | 1 + STRUCTURE.tree | 9 +- crates/brain-core/Cargo.toml | 3 + crates/brain-core/src/lib.rs | 27 ++++++ crates/brain-grpc/Cargo.toml | 1 + crates/brain-grpc/src/server.rs | 15 ++- crates/brain-proto/build.rs | 5 +- crates/brain-proto/src/lib.rs | 12 ++- proto/echo/vtuber/voice/v1/voice.proto | 18 ---- 10 files changed, 183 insertions(+), 32 deletions(-) delete mode 100644 proto/echo/vtuber/voice/v1/voice.proto diff --git a/Cargo.lock b/Cargo.lock index dc735e9..a42d036 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -124,11 +124,17 @@ checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" [[package]] name = "brain-core" version = "0.1.0" +dependencies = [ + "serde", + "tracing", + "vtuber-commons", +] [[package]] name = "brain-grpc" version = "0.1.0" dependencies = [ + "brain-core", "brain-proto", "tokio", "tonic", @@ -418,6 +424,25 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" +[[package]] +name = "include_dir" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd" +dependencies = [ + "include_dir_macros", +] + +[[package]] +name = "include_dir_macros" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "indexmap" version = "1.9.3" @@ -776,6 +801,12 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + [[package]] name = "scopeguard" version = "1.2.0" @@ -795,6 +826,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", + "serde_derive", ] [[package]] @@ -830,6 +862,28 @@ dependencies = [ "zmij", ] +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap 2.14.0", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "signal-hook-registry" version = "1.4.8" @@ -954,6 +1008,47 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap 2.14.0", + "serde", + "serde_spanned", + "toml_datetime", + "toml_write", + "winnow", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + [[package]] name = "tonic" version = "0.12.3" @@ -1093,6 +1188,26 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "vtuber-commons" +version = "0.0.1" +source = "sparse+http://kellnr.cntm.labs:31500/api/v1/crates/" +checksum = "862a0e58bc5b427ab5ff1bd0468ebf3f7b69bcdef41b351f63ead7ccdabe7f3b" +dependencies = [ + "include_dir", + "serde", + "serde_json", + "serde_yaml", + "toml", + "vtuber-contracts", +] + [[package]] name = "vtuber-contracts" version = "0.1.0" @@ -1260,6 +1375,15 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] + [[package]] name = "wit-bindgen" version = "0.51.0" diff --git a/Cargo.toml b/Cargo.toml index a911d92..aa34435 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,3 +17,4 @@ serde_json = "1.0" tracing = "0.1" tracing-subscriber = "0.3" vtuber-contracts = { version = "0.1.0", registry = "vtuber-registry" } +vtuber-commons = { version = "0.0.1", registry = "vtuber-registry" } diff --git a/STRUCTURE.tree b/STRUCTURE.tree index d2516bc..0b6f805 100644 --- a/STRUCTURE.tree +++ b/STRUCTURE.tree @@ -63,12 +63,9 @@ ├── proto │   └── echo │   └── vtuber -│   ├── brain -│   │   └── v1 -│   │   └── brain.proto -│   └── voice +│   └── brain │   └── v1 -│   └── voice.proto +│   └── brain.proto ├── README.md ├── ROADMAP.md ├── SECURITY.md @@ -78,4 +75,4 @@ ├── TROUBLESHOOTING.md └── VISION.md -27 directories, 52 files +25 directories, 51 files diff --git a/crates/brain-core/Cargo.toml b/crates/brain-core/Cargo.toml index d7a70a5..106d62d 100644 --- a/crates/brain-core/Cargo.toml +++ b/crates/brain-core/Cargo.toml @@ -4,3 +4,6 @@ version = "0.1.0" edition = "2021" [dependencies] +vtuber-commons = { workspace = true } +serde = { workspace = true } +tracing = { workspace = true } diff --git a/crates/brain-core/src/lib.rs b/crates/brain-core/src/lib.rs index 8b13789..b451284 100644 --- a/crates/brain-core/src/lib.rs +++ b/crates/brain-core/src/lib.rs @@ -1 +1,28 @@ +use tracing::info; +use vtuber_commons::assets::personas; +pub struct LoreManager { + pub active_persona: String, +} + +impl LoreManager { + pub fn new() -> Self { + info!("Initializing LoreManager with assets from vtuber-commons"); + // Using the SAMPLE persona from vtuber-commons + let persona_data = personas::SAMPLE; + + Self { + active_persona: persona_data.to_string(), + } + } + + pub fn get_lore(&self) -> &str { + &self.active_persona + } +} + +impl Default for LoreManager { + fn default() -> Self { + Self::new() + } +} diff --git a/crates/brain-grpc/Cargo.toml b/crates/brain-grpc/Cargo.toml index 630fd1c..dc894ad 100644 --- a/crates/brain-grpc/Cargo.toml +++ b/crates/brain-grpc/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] brain-proto = { path = "../brain-proto" } +brain-core = { path = "../brain-core" } tonic = { workspace = true } tokio = { workspace = true } tracing = { workspace = true } diff --git a/crates/brain-grpc/src/server.rs b/crates/brain-grpc/src/server.rs index b32ed48..ee96fbe 100644 --- a/crates/brain-grpc/src/server.rs +++ b/crates/brain-grpc/src/server.rs @@ -1,9 +1,19 @@ +use brain_core::LoreManager; use brain_proto::brain::v1::brain_service_server::BrainService; use brain_proto::brain::v1::{PushContextRequest, PushContextResponse}; use tonic::{Request, Response, Status}; -#[derive(Default)] -pub struct MyBrainService {} +pub struct MyBrainService { + pub lore: LoreManager, +} + +impl Default for MyBrainService { + fn default() -> Self { + Self { + lore: LoreManager::new(), + } + } +} #[tonic::async_trait] impl BrainService for MyBrainService { @@ -12,6 +22,7 @@ impl BrainService for MyBrainService { request: Request, ) -> Result, Status> { let r = request.into_inner(); + tracing::info!("Reasoning with persona lore: {}", self.lore.get_lore()); tracing::info!("Received context from {}: {}", r.user_id, r.message); Ok(Response::new(PushContextResponse { diff --git a/crates/brain-proto/build.rs b/crates/brain-proto/build.rs index 25fd8c5..356154a 100644 --- a/crates/brain-proto/build.rs +++ b/crates/brain-proto/build.rs @@ -3,10 +3,7 @@ fn main() -> Result<(), Box> { .build_server(true) .build_client(true) .compile_protos( - &[ - "../../proto/echo/vtuber/brain/v1/brain.proto", - "../../proto/echo/vtuber/voice/v1/voice.proto", - ], + &["../../proto/echo/vtuber/brain/v1/brain.proto"], &["../../proto"], )?; Ok(()) diff --git a/crates/brain-proto/src/lib.rs b/crates/brain-proto/src/lib.rs index 4745e37..52130e4 100644 --- a/crates/brain-proto/src/lib.rs +++ b/crates/brain-proto/src/lib.rs @@ -1,11 +1,19 @@ +pub use vtuber_contracts::vtuber; + pub mod brain { pub mod v1 { + // Use local definition until merged into vtuber-contracts (Issue #9) tonic::include_proto!("echo.vtuber.brain.v1"); } } -pub mod voice { +pub mod director { pub mod v1 { - tonic::include_proto!("echo.vtuber.voice.v1"); + // Mapping to what's actually in vtuber-contracts v0.1.0 + pub use vtuber_contracts::vtuber::v1::{ + director_service_client::DirectorServiceClient, + director_service_server::{DirectorService, DirectorServiceServer}, + EmitDirectiveRequest, EmitDirectiveResponse, + }; } } diff --git a/proto/echo/vtuber/voice/v1/voice.proto b/proto/echo/vtuber/voice/v1/voice.proto deleted file mode 100644 index b0254fb..0000000 --- a/proto/echo/vtuber/voice/v1/voice.proto +++ /dev/null @@ -1,18 +0,0 @@ -syntax = "proto3"; - -package echo.vtuber.voice.v1; - -// VoiceService defines the interface for the Performer (vtuber-voice) to receive directives. -service VoiceService { - rpc EmitDirective (EmitDirectiveRequest) returns (EmitDirectiveResponse); -} - -message EmitDirectiveRequest { - string text_prompt = 1; - string voice_prompt = 2; - map commands = 3; -} - -message EmitDirectiveResponse { - bool success = 1; -} From 60e526396a7804806d977b8ffdfaef91b6d22e02 Mon Sep 17 00:00:00 2001 From: MrBT-nano Date: Sun, 10 May 2026 21:15:47 +0700 Subject: [PATCH 5/6] fix: add registry setup step to CI and security workflows --- .github/workflows/ci.yml | 16 ++++++++++++++++ .github/workflows/security.yml | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6c1ec16..c86fbb2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,6 +40,14 @@ jobs: - name: Install dependencies if: steps.guard.outputs.skip != 'true' run: sudo apt-get update && sudo apt-get install -y protobuf-compiler + - name: Setup Private Registry + if: steps.guard.outputs.skip != 'true' + run: | + mkdir -p .cargo + cat < .cargo/config.toml + [registries.vtuber-registry] + index = "sparse+http://kellnr.cntm.labs:31500/api/v1/crates/" + EOF - name: Setup Rust if: steps.guard.outputs.skip != 'true' uses: dtolnay/rust-toolchain@stable @@ -69,6 +77,14 @@ jobs: - name: Install dependencies if: steps.guard.outputs.skip != 'true' run: sudo apt-get update && sudo apt-get install -y protobuf-compiler + - name: Setup Private Registry + if: steps.guard.outputs.skip != 'true' + run: | + mkdir -p .cargo + cat < .cargo/config.toml + [registries.vtuber-registry] + index = "sparse+http://kellnr.cntm.labs:31500/api/v1/crates/" + EOF - name: Setup Rust if: steps.guard.outputs.skip != 'true' uses: dtolnay/rust-toolchain@stable diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 496342f..076b956 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -35,6 +35,14 @@ jobs: else echo "skip=false" >> $GITHUB_OUTPUT fi + - name: Setup Private Registry + if: steps.guard.outputs.skip != 'true' + run: | + mkdir -p .cargo + cat < .cargo/config.toml + [registries.vtuber-registry] + index = "sparse+http://kellnr.cntm.labs:31500/api/v1/crates/" + EOF - name: Setup Rust if: steps.guard.outputs.skip != 'true' uses: dtolnay/rust-toolchain@stable @@ -66,6 +74,14 @@ jobs: - name: Install dependencies if: steps.guard.outputs.skip != 'true' run: sudo apt-get update && sudo apt-get install -y protobuf-compiler + - name: Setup Private Registry + if: steps.guard.outputs.skip != 'true' + run: | + mkdir -p .cargo + cat < .cargo/config.toml + [registries.vtuber-registry] + index = "sparse+http://kellnr.cntm.labs:31500/api/v1/crates/" + EOF - name: Setup Rust if: steps.guard.outputs.skip != 'true' uses: dtolnay/rust-toolchain@stable From 31dbb5afe31e0905bc2eed95277483e9b0d59e45 Mon Sep 17 00:00:00 2001 From: MrBT-nano Date: Tue, 12 May 2026 13:26:58 +0700 Subject: [PATCH 6/6] chore: migrate all workflows to self-hosted runners --- .github/workflows/badges.yml | 2 +- .github/workflows/ci.yml | 8 ++++---- .github/workflows/pr_automation.yml | 2 +- .github/workflows/security.yml | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/badges.yml b/.github/workflows/badges.yml index c259c37..c9a2fe2 100644 --- a/.github/workflows/badges.yml +++ b/.github/workflows/badges.yml @@ -15,7 +15,7 @@ permissions: jobs: refresh: name: Refresh LOD counts from current repo - runs-on: ubuntu-latest + runs-on: self-hosted if: "!contains(github.event.head_commit.message, '[skip ci]')" steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c86fbb2..a7b9558 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ on: jobs: bootstrap-smoke-test: name: Bootstrap smoke test - runs-on: ubuntu-latest + runs-on: self-hosted steps: - uses: actions/checkout@v4 - name: Detect source stacks @@ -25,7 +25,7 @@ jobs: rust-lint: name: Rust Lint & Format - runs-on: ubuntu-latest + runs-on: self-hosted steps: - uses: actions/checkout@v4 - name: Skip if no Cargo.toml @@ -62,7 +62,7 @@ jobs: rust-build-and-test: name: Rust Build & Test - runs-on: ubuntu-latest + runs-on: self-hosted steps: - uses: actions/checkout@v4 - name: Skip if no Cargo.toml @@ -107,7 +107,7 @@ jobs: mojo-build: name: Mojo Build & Test - runs-on: ubuntu-latest + runs-on: self-hosted steps: - uses: actions/checkout@v4 - name: Mojo build (skipped until mojoproject.toml exists) diff --git a/.github/workflows/pr_automation.yml b/.github/workflows/pr_automation.yml index 49acb8a..73255f8 100644 --- a/.github/workflows/pr_automation.yml +++ b/.github/workflows/pr_automation.yml @@ -6,7 +6,7 @@ on: jobs: metadata: name: Label & Assign - runs-on: ubuntu-latest + runs-on: self-hosted permissions: pull-requests: write contents: read diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 076b956..4c9f87e 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -14,7 +14,7 @@ permissions: jobs: security-smoke-test: name: Security baseline - runs-on: ubuntu-latest + runs-on: self-hosted steps: - uses: actions/checkout@v4 - name: Baseline check @@ -23,7 +23,7 @@ jobs: rust-audit: name: Rust Dependency Audit - runs-on: ubuntu-latest + runs-on: self-hosted steps: - uses: actions/checkout@v4 - name: Skip if no Cargo.toml @@ -55,7 +55,7 @@ jobs: rust-clippy-security: name: Rust Static Analysis (SARIF) - runs-on: ubuntu-latest + runs-on: self-hosted permissions: contents: read security-events: write @@ -107,7 +107,7 @@ jobs: mojo-security: name: Mojo Security Check - runs-on: ubuntu-latest + runs-on: self-hosted steps: - uses: actions/checkout@v4 - name: Mojo static analysis (skipped until mojoproject.toml exists)