/archestra-dev-rust-napi
Use when editing Rust in this repo — the NAPI crates under platform/archestra-rs (app-runtime, image, and sandbox core/-rs crate pairs plus napi-loader, with their generated TypeScript bindings) or the standalone ai-labs Rust workspace (core/runner/cli/analyzer/dashboard) —
$ npx -y skills add archestra-ai/archestra --skill archestra-dev-rust-napi --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/archestra-dev-rust-napi
Context preview
The summary Claude sees to decide when to auto-load this skill.
Use when editing Rust in this repo — the NAPI crates under platform/archestra-rs (app-runtime, image, and sandbox core/-rs crate pairs plus napi-loader, with their generated TypeScript bindings) or the standalone ai-labs Rust workspace (core/runner/cli/analyzer/dashboard) —
SKILL.md
archestra-dev-rust-napi.SKILL.mdname: archestra-dev-rust-napi
description: Use when editing Rust in this repo — the NAPI crates under platform/archestra-rs (app-runtime, image, and sandbox core/-rs crate pairs plus napi-loader, with their generated TypeScript bindings) or the standalone ai-labs Rust workspace (core/runner/cli/analyzer/dashboard) — including Rust build/test checks.
Archestra Rust Coding Style
This covers all Rust in the repo:
- `platform/archestra-rs/*` — embedded in Node via NAPI.
- `ai-labs/*` — a standalone pure-Rust workspace (core/runner/cli/analyzer/dashboard), no NAPI.
The library-quality rules below apply everywhere. Rules tagged **(NAPI only)** apply only to Rust embedded via NAPI.
Write Rust as a reusable library first. For NAPI crates the binding is a thin adapter around a Node-free core — deleting or replacing the NAPI layer should not delete or rewrite the product logic. The bench crates are already standalone Rust, so the same core-quality bar applies to them directly.
Default posture: boring Rust
Rust is a normal product language here, not a type-system puzzle. The first correct version should be boring and explicit.
Prefer plain functions, concrete structs, enums for closed states, newtypes for domain identifiers, `Option<T>`/`Result<T, E>`, owned data at public boundaries and borrowed data inside small internal functions, and small modules named after domain concepts.
Avoid by default: custom macros, actor frameworks, hidden global registries, smart-pointer graphs, runtime type erasure, and clever lifetime-heavy public APIs. (See Abstractions for trait-object and generics rules.)
Do not make Rust code look like Java, TypeScript DI, or Haskell cosplay.
Architecture
Applies to all Rust:
- Minimize the public API surface. Prefer a few coarse operations over many tiny exported helpers.
- Keep observability in the core as `tracing` spans and events only.
- OTLP/exporter wiring belongs in a single feature-gated module, never scattered through the logic.
- Propagate trace context, such as W3C `traceparent`, explicitly across detached tasks and actor boundaries. It does not flow implicitly.
**(NAPI only)** boundary rules:
- Keep core Rust logic independent from Node, JavaScript, and NAPI. No `#[napi]`, `napi::Result`, JS types, or Node-specific assumptions in core modules.
- NAPI functions should only receive JS input, validate and convert it into Rust domain types, call the Rust core, and convert the result or error back to JS.
- Do not expose internal implementation details through the NAPI API.
- Generated TypeScript definitions are part of the public API and should stay clean, stable, and intentional.
Types and data modeling
- Prefer structs, enums, and newtypes over primitive-heavy signatures, tuples, raw strings, boolean flags, and long positional argument lists.
- Use enums for closed sets of states or modes.
- Make invalid states unrepresentable where practical.
- Treat all external input as untrusted (JS input at the NAPI boundary; argv, files, and network/process output in the bench).
- Validate untrusted input at the public entry points and convert it immediately into Rust-native types, not deep in the call graph.
- Data validated when first accepted, such as persisted or replayed history, is trusted on reuse. Document that trust boundary wherever it is not obvious.
- Keep boundary-facing DTOs separate from richer internal domain types when that improves clarity.
Ownership defaults
Start with values, references, and clear ownership.
- Public domain structs should usually own their data.
- Avoid public structs with lifetime parameters unless there is a clear performance or API reason.
- Cloning small strings, IDs, config values, and DTO fields is acceptable when it keeps ownership simple.
- Do not clone large buffers, request bodies, process output, or hot-path data without a reason.
- Do not use `Box<T>` unless the type is recursive, very large, or must be behind a stable pointer.
- Do not use `Rc<T>` or `RefCell<T>` in product logic unless modeling a local graph/tree where ownership is inherently shared.
- Do not use `Arc<T>` unless data must cross task or thread boundaries.
- Do not use `Arc<Mutex<T>>` as a default escape hatch. If used, document what is shared, who locks it, and why message passing or single ownership is worse.
- Never hold a lock across `.await`.
- Do not use `Pin`, self-referential structs, or unsafe lifetime tricks unless explicitly requested and reviewed.
- Do not add indirection to avoid understanding ownership. Fix the ownership model instead.
Control flow and style
- Prefer `match` for enums, variants, and meaningful branching.
- Prefer early returns for validation and error paths.
- Avoid deeply nested control flow.
- Prefer functional style where it reads better, but do not force iterator chains when a simple loop is clearer.
Abstractions
Abstractions must pay rent immediately.
- Do not introduce a trait unless there are at least two real implementations today, or it represents a real boundary such as storage, process execution, clock/time, network I/O, or NAPI adapter isolation.
- Do not create `FooService`, `FooManager`, `FooProvider`, or `FooFactory` traits just to make testing easier. Prefer passing concrete input data, small pure functions, or explicit test fixtures.
- Avoid `dyn Trait`. Use concrete types first, an enum when the set of implementations is closed, and generics only when the caller truly needs static polymorphism. `dyn Trait` requires a written justification in the PR summary: why runtime polymorphism is needed, what the concrete implementations are, and why an enum or concrete type is worse.
- Avoid `async_trait` unless integrating with an existing async trait API. Prefer concrete async functions.
- Do not add generic type parameters unless there are multiple real call sites with different concrete types, or the generic is a standard Rust convenience such as accepting a path-like in
Read more
name: archestra-dev-rust-napi description: Use when editing Rust in this repo — the NAPI crates under platform/archestra-rs (app-runtime, image, and sandbox core/-rs crate pairs plus napi-loader, with their generated TypeScript bindings) or the standalone ai-labs Rust workspace (core/runner/cli/analyzer/dashboard) — including Rust build/test checks.
Archestra Rust Coding Style
This covers all Rust in the repo:
- `platform/archestra-rs/*` — embedded in Node via NAPI.
- `ai-labs/*` — a standalone pure-Rust workspace (core/runner/cli/analyzer/dashboard), no NAPI.
The library-quality rules below apply everywhere. Rules tagged **(NAPI only)** apply only to Rust embedded via NAPI.
Write Rust as a reusable library first. For NAPI crates the binding is a thin adapter around a Node-free core — deleting or replacing the NAPI layer should not delete or rewrite the product logic. The bench crates are already standalone Rust, so the same core-quality bar applies to them directly.
Default posture: boring Rust
Rust is a normal product language here, not a type-system puzzle. The first correct version should be boring and explicit.
Prefer plain functions, concrete structs, enums for closed states, newtypes for domain identifiers, `Option<T>`/`Result<T, E>`, owned data at public boundaries and borrowed data inside small internal functions, and small modules named after domain concepts.
Avoid by default: custom macros, actor frameworks, hidden global registries, smart-pointer graphs, runtime type erasure, and clever lifetime-heavy public APIs. (See Abstractions for trait-object and generics rules.)
Do not make Rust code look like Java, TypeScript DI, or Haskell cosplay.
Architecture
Applies to all Rust:
- Minimize the public API surface. Prefer a few coarse operations over many tiny exported helpers.
- Keep observability in the core as `tracing` spans and events only.
- OTLP/exporter wiring belongs in a single feature-gated module, never scattered through the logic.
- Propagate trace context, such as W3C `traceparent`, explicitly across detached tasks and actor boundaries. It does not flow implicitly.
**(NAPI only)** boundary rules:
- Keep core Rust logic independent from Node, JavaScript, and NAPI. No `#[napi]`, `napi::Result`, JS types, or Node-specific assumptions in core modules.
- NAPI functions should only receive JS input, validate and convert it into Rust domain types, call the Rust core, and convert the result or error back to JS.
- Do not expose internal implementation details through the NAPI API.
- Generated TypeScript definitions are part of the public API and should stay clean, stable, and intentional.
Types and data modeling
- Prefer structs, enums, and newtypes over primitive-heavy signatures, tuples, raw strings, boolean flags, and long positional argument lists.
- Use enums for closed sets of states or modes.
- Make invalid states unrepresentable where practical.
- Treat all external input as untrusted (JS input at the NAPI boundary; argv, files, and network/process output in the bench).
- Validate untrusted input at the public entry points and convert it immediately into Rust-native types, not deep in the call graph.
- Data validated when first accepted, such as persisted or replayed history, is trusted on reuse. Document that trust boundary wherever it is not obvious.
- Keep boundary-facing DTOs separate from richer internal domain types when that improves clarity.
Ownership defaults
Start with values, references, and clear ownership.
- Public domain structs should usually own their data.
- Avoid public structs with lifetime parameters unless there is a clear performance or API reason.
- Cloning small strings, IDs, config values, and DTO fields is acceptable when it keeps ownership simple.
- Do not clone large buffers, request bodies, process output, or hot-path data without a reason.
- Do not use `Box<T>` unless the type is recursive, very large, or must be behind a stable pointer.
- Do not use `Rc<T>` or `RefCell<T>` in product logic unless modeling a local graph/tree where ownership is inherently shared.
- Do not use `Arc<T>` unless data must cross task or thread boundaries.
- Do not use `Arc<Mutex<T>>` as a default escape hatch. If used, document what is shared, who locks it, and why message passing or single ownership is worse.
- Never hold a lock across `.await`.
- Do not use `Pin`, self-referential structs, or unsafe lifetime tricks unless explicitly requested and reviewed.
- Do not add indirection to avoid understanding ownership. Fix the ownership model instead.
Control flow and style
- Prefer `match` for enums, variants, and meaningful branching.
- Prefer early returns for validation and error paths.
- Avoid deeply nested control flow.
- Prefer functional style where it reads better, but do not force iterator chains when a simple loop is clearer.
Abstractions
Abstractions must pay rent immediately.
- Do not introduce a trait unless there are at least two real implementations today, or it represents a real boundary such as storage, process execution, clock/time, network I/O, or NAPI adapter isolation.
- Do not create `FooService`, `FooManager`, `FooProvider`, or `FooFactory` traits just to make testing easier. Prefer passing concrete input data, small pure functions, or explicit test fixtures.
- Avoid `dyn Trait`. Use concrete types first, an enum when the set of implementations is closed, and generics only when the caller truly needs static polymorphism. `dyn Trait` requires a written justification in the PR summary: why runtime polymorphism is needed, what the concrete implementations are, and why an enum or concrete type is worse.
- Avoid `async_trait` unless integrating with an existing async trait API. Prefer concrete async functions.
- Do not add generic type parameters unless there are multiple real call sites with different concrete types, or the generic is a standard Rust convenience such as accepting a path-like in
Enterprise AI Platform with guardrails, MCP registry, gateway & orchestrator
Repo: archestra-ai/archestra
Other skills on archestra.
- /archestra-dev-backend-tests
Use when writing or modifying Archestra backend unit tests (platform/backend/src/**/*.test.ts) — mocking modules, stubbing globals, database fixtures, vitest projects/isolation, or test performance.
Open skill - /archestra-dev-backend
Use when adding or changing Archestra backend routes, models, services, API request/response schemas, endpoint permissions, or OpenAPI/codegen for the generated API client.
Open skill - /archestra-dev-bench-analysis
Map-reduce a finished archestra-bench run into a Tier-1/Tier-2 improvement report using Claude subagents (same analysis as the Rust analyzer, no API key).
Open skill - /archestra-dev-e2e
Use when writing, debugging, or running Archestra Playwright e2e tests, API/UI fixtures, WireMock-backed tests, local/CI e2e setup, or test selectors.
Open skill - /archestra-dev-frontend
Use when modifying Archestra frontend Next.js/React code, UI components, forms, TanStack Query hooks, generated API client usage, frontend copy, or documentation links.
Open skill - /archestra-dev-interactions-migrations
Use BEFORE writing or running any Drizzle migration that touches the `interactions` table (or any other very large, write-hot table). The interactions table is the platform's biggest, append-heavy table — every LLM proxy call writes a row — so a careless migration can take a
Open skill

