Navi Programming Language Expert

VerifiedSafe

Expert in the Navi programming language: a high-performance, statically-typed compiled language with no NULL pointers, modern optional types, and built-in concurrency via `spawn` and channels. Covers syntax essentials (string interpolation, error handling with `throws`/`try`, control flow limitations like non-expressive `if`/`switch`). Helps write correct Navi code, especially for optionals, structs, maps, and concurrency.

Sby Skills Guide Bot
DevelopmentIntermediate
6/2/2026
Claude Code
#navi#statically-typed#compiled#concurrency

Recommended for

Automated summary

Expert in the Navi language, a statically-typed compiled language with no NULL pointer exceptions and built-in concurrency support.

Strengths

  • No NULL pointer exceptions thanks to modern optional types
  • Comprehensive error handling with throws, try, try?
  • Built-in concurrency with spawn and channels
  • Compiled performance comparable to Go, Rust, and C

Limitations

  • If and switch are statements, not expressions, limiting assignment use
  • Scientific notation requires explicit sign
  • Single-threaded concurrency (spawn) is limited compared to Go's goroutines
When to use it

Use this skill when writing, debugging, or optimizing Navi code for high-performance applications requiring reliability with no null pointer issues.

When not to use it

Avoid this skill if you need expression-oriented control flow or a mature ecosystem with extensive libraries.

Security analysis

Safe
Quality score90/100

The skill is purely instructional documentation for the Navi programming language, with no executable actions, destructive commands, or data exfiltration risks.

No concerns found

How this analysis is made

Examples

Write a Navi function with error handling
Write a Navi function that reads a file and returns its contents, handling possible errors properly using throws and try.
Explain Navi optional types
Explain how optional types work in Navi and show examples of safe unwrapping with ||, ?., and !.
Debug Navi control flow syntax
Why does this Navi code give a syntax error? let status = if (active) { 'on' } else { 'off' };

name: navi description: Navi programming language expert. Use when writing Navi code, implementing features, handling errors, or working with Navi's type system, concurrency, and modules. Navi is a high-performance, statically-typed compiled language with modern optional types, no NULL pointer exceptions, and built-in concurrency support.

Navi Language Skill

Navi (/ˈnævi/) is a high-performance, statically-typed compiled language designed for complex computing tasks. It offers script-like execution with compiled performance comparable to Go, Rust, and C.

Core Characteristics

  • Statically typed with type inference
  • No NULL pointer exceptions - once compiled, code runs reliably
  • Modern optional types (similar to Rust's Option)
  • Comprehensive error handling with throws, try, try?, try!
  • Built-in concurrency with spawn and channels (single-threaded concurrency)
  • Cross-platform: Linux, Windows, macOS, WebAssembly

Quick Reference

Basic Syntax

// Entry point (main must have throws)
fn main() throws {
    let name = "World";
    let message = `Hello ${name}.`;  // String interpolation
    println(message);  // Auto-imported from std.io
}

// Functions
fn add(a: int, b: int): int {
    return a + b;
}

// Structs
struct User {
    name: string,
    email: string?,  // Optional field
    active: bool = true,  // Default value
}

impl User {
    fn new(name: string): User {
        return User { name, email: nil };
    }
}

Key Syntax Rules

  • Statements end with ;
  • Use 4 spaces for indentation
  • // for single-line comments, /// for doc comments
  • String interpolation uses backticks: `value: ${x}`
  • File extension: .nv

Important Syntax Limitations

If and Switch are STATEMENTS, not expressions:

// ❌ WRONG - Cannot assign if/switch directly
let status = if (active) { "on" } else { "off" };
let day = switch (n) { case 1: "Mon"; default: "Other"; };

// ✅ CORRECT - Use statements, then assign
let status = "";
if (active) {
    status = "on";
} else {
    status = "off";
}

Scientific notation requires explicit sign:

// ❌ WRONG
let num = 1.5e10;

// ✅ CORRECT
let num = 1.5e+10;  // or 1.5e-10 for negative exponent

Map access with [] vs .get():

let scores = {"Alice": 95, "Bob": 87};

// ❌ WRONG - scores["key"] returns non-optional, can't use ||
let score = scores["Eve"] || 0;

// ✅ CORRECT - Use .get() which returns optional type
let score = scores.get("Eve") || 0;

// ✅ Also correct - Direct access (but key must exist)
let alice_score = scores["Alice"];  // OK if key exists

// ✅ Also correct - Check before access
if (scores.get("Eve") != nil) {
    let score = scores["Eve"];
}

Type System Essentials

// Primitives (all 64-bit)
let n: int = 100;
let f: float = 3.14;
let b: bool = true;
let s: string = "text";  // Immutable UTF-8
let c: char = '🎉';

// Optional types (key to NULL safety)
let value: string? = nil;
let result = value || "default";  // Unwrap or default
let length = value?.len();  // Safe chaining (returns nil if value is nil)
println(value!);  // Unwrap (panics if nil - use sparingly)

// Collections
let array = [1, 2, 3];
let map = {"key": "value"};
let empty: [int] = [];

Error Handling Pattern

// Declare function can throw
fn divide(a: int, b: int): int throws {
    if (b == 0) {
        throw "Division by zero";
    }
    return a / b;
}

// Handle errors
let result = try? divide(10, 0);  // Returns int? (nil on error)
let result = try divide(10, 2);   // Propagate error up
let result = try! divide(10, 2);  // Panic on error

// Do-catch block
do {
    let r = try divide(10, 0);
} catch (e) {
    println(e.error());
}

Control Flow Patterns

// If-let for optionals
if (let value = optional) {
    println(value);  // value is unwrapped here
}

// Let-else for early returns
let value = optional else {
    return;
};
// value is unwrapped here

// Switch with type matching
switch (let v = value.(type)) {
    case int:
        println("integer");
    case string:
        println("string");
    default:
        println("other");
}

// For loops
for (let i in 0..10) {  // Range
    println(`${i}`);
}

for (let item in array) {  // Array
    println(item);
}

for (let k, v in map) {  // Map
    println(`${k}: ${v}`);
}

Concurrency Basics

use std.time;

fn main() throws {
    let ch = channel::<int>();

    // Spawn concurrent task (not parallel - single thread)
    spawn {
        time.sleep(0.1.seconds());
        try! ch.send(42);
    }

    let result = try ch.recv();
    println(`${result}`);
}

Worker Pattern

use std.worker.Worker;

fn main() throws {
    // Create worker with closure
    let worker = try Worker.create(|worker| {
        let msg = try worker.recv::<string>()!;
        try worker.send(msg.to_uppercase());
    });

    try worker.send("hello");
    let response = try worker.recv::<string>();
    println(response);  // "HELLO"
}

Navi Stream Integration

use nvs.macd;  // Import .nvs file as module

fn main() throws {
    // Create instance of NVS indicator
    let indicator = macd.new();

    // Execute with market data
    indicator.execute(
        time: 1234567890,
        open: 100.0,
        high: 105.0,
        low: 99.0,
        close: 103.0,
        volume: 1000.0,
        turnover: 100000.0
    );

    // Access exported variables
    println(`hist=${indicator.hist:?}`);
    println(`signal=${indicator.signal:?}`);
    println(`macd=${indicator.macd:?}`);
}

Variadic Arguments

// Accept arbitrary number of arguments
fn sum(values: ..int): int {
    let total = 0;
    for (let n in values) {
        total += n;
    }
    return total;
}

sum(1, 2, 3);           // Call with multiple args
let nums = [2, 3, 4];
sum(..nums);            // Spread array
sum(1, ..nums, 5);      // Mix regular and spread

// With other parameters
fn format(prefix: string, parts: ..string): string {
    return prefix + parts.join(",");
}

Common Patterns

Safe Optional Handling

// Pattern 1: Unwrap or default
let name = user?.name || "Unknown";

// Pattern 2: If-let
if (let user = optional_user) {
    process(user);
}

// Pattern 3: Let-else (early return)
let user = optional_user else {
    return;
};
process(user);

// Pattern 4: Method chaining
let email = user?.profile?.email || "none";

Resource Management

fn process_file(path: string) throws {
    let file = try open_file(path);

    defer {
        file.close();  // Always runs when function exits
    }

    try file.read();
    // defer executes here (LIFO if multiple defer blocks)
}

Builder Pattern

impl Config {
    fn new(): Config {
        return Config { /* defaults */ };
    }

    fn with_port(self, port: int): Config {
        self.port = port;
        return self;
    }
}

let config = Config.new().with_port(8080);

CLI Commands

navi run              # Run main.nv
navi run file.nv      # Run specific file
navi test             # Run all tests
navi test file.nv     # Run tests in file
navi test --doc       # Run doc tests
navi build            # Build project
navi compile          # Show bytecode

Testing

test "addition" {
    let result = add(2, 3);
    assert result == 5;
    assert_eq result, 5;
    assert_ne result, 0;
}

/// Doc test example
/// ```nv
/// assert_eq add(1, 2), 3;
/// ```
fn add(a: int, b: int): int {
    return a + b;
}

Best Practices

Naming Conventions

  • snake_case: variables, functions, fields (user_name, get_user)
  • CamelCase: types, structs, enums (User, HttpRequest)
  • SCREAMING_SNAKE_CASE: constants (MAX_SIZE)

When to Use Each Error Handler

  • try - When error should propagate up (most common)
  • try? - When failure is acceptable, convert to optional
  • try! - When failure is unexpected (use sparingly)
  • do-catch - When you need custom error handling logic

Optional Type Guidelines

  • Use || for simple defaults
  • Use ?. for safe chaining
  • Prefer if let for conditional logic
  • Use let else for early returns

Concurrency Notes

  • spawn is concurrent, not parallel (single-threaded)
  • Tasks interleave but don't run simultaneously
  • Use channels for communication between tasks
  • Blocking operations block entire runtime

When to Load References

Load reference files when you need detailed information:

  • syntax.md - Full syntax reference with all language constructs
  • types.md - Complete type system including interfaces, unions, type aliases
  • error-handling.md - Comprehensive error handling patterns and custom errors
  • concurrency.md - Advanced concurrency patterns, channels, and spawn details
  • modules.md - Module system, imports, visibility rules
  • testing.md - Testing framework, annotations, doc tests
  • patterns.md - Common idiomatic patterns and anti-patterns

Use Read tool to load these files from ~/.claude/skills/navi/references/ when needed.

Resources

  • Official Site: https://navi-lang.org
  • Standard Library: https://navi-lang.org/stdlib/
  • GitHub: https://github.com/navi-language/navi
  • Installation: curl -sSL https://navi-lang.org/install | sh

From the file to a first result

The download contains exactly the content displayed on this page. This copy may differ from the latest version in the source repository.

View the source and supporting files

This download contains SKILL.md only. Any scripts, references, templates and dependencies are not included. Get the required files from the source, preserving their directory structure, before continuing.

1. Download the file

Download SKILL.md

From the root of a test project, save the file as .skill-downloads/navi-programming-language-expert-mm5t89c4/SKILL.md, or use the command below. This folder is for inspecting the skill before installation.

Command for macOS/Linux or WSL: requires a POSIX shell and curl. On Windows without WSL, use the download button and create the folder manually.

mkdir -p '.skill-downloads/navi-programming-language-expert-mm5t89c4' && curl --fail --show-error --location 'https://skills-guides.com/api/skills/navi-programming-language-expert-mm5t89c4/download' --output '.skill-downloads/navi-programming-language-expert-mm5t89c4/SKILL.md.part' && mv '.skill-downloads/navi-programming-language-expert-mm5t89c4/SKILL.md.part' '.skill-downloads/navi-programming-language-expert-mm5t89c4/SKILL.md'

2. Check prerequisites

Read SKILL.md before using it. If it references scripts or external services, inspect them and prepare the required access in your test environment.

Original excerpt: Quick Reference

Basic Syntax

// Entry point (main must have throws)
fn main() throws {
    let name = "World";
    let message = `Hello ${name}.`;  // String interpolation
    println(message);  // Auto-imported from std.io
}

// Functions
fn add(a: int, b: int): int {
    return a + b;
}

// Structs
struct User {
    name: string,
    email: string?,  // Optional field
    active: bool = true,  // Default value
}

impl User {
    fn new(name: string): User {
        return User { name, email: nil };
    }
}

Key Syntax Rules

  • Statements end with ;
  • Use 4 spaces for indentation
  • // for single-line comments, /// for doc comments
  • String interpolation uses backticks: `value: ${x}`
  • File extension: .nv

Important Syntax Limitations

If and Switch are STATEMENTS, not expressions:

// ❌ WRONG - Cannot assign if/switch directly
let status = if (active) { "on" } else { "off" };
let day = switch (n) { case 1: "Mon"; default: "Other"; };

// ✅ CORRECT - Use statements, then assign
let status = "";
if (active) {
    status = "on";
} else {
    status = "off";
}

Scientific notation requires explicit sign:

// ❌ WRONG
let num = 1.5e10;

// ✅ CORRECT
let num = 1.5e+10;  // or 1.5e-10 for negative exponent

Map access with [] vs .get():

let scores = {"Alice": 95, "Bob": 87};

// ❌ WRONG - scores["key"] returns non-optional, can't use ||
let score = scores["Eve"] || 0;

// ✅ CORRECT - Use .get() which returns optional type
let score = scores.get("Eve") || 0;

// ✅ Also correct - Direct access (but key must exist)
let alice_score = scores["Alice"];  // OK if key exists

// ✅ Also correct - Check before access
if (scores.get("Eve") != nil) {
    let score = scores["Eve"];
}

Type System Essentials

// Primitives (all 64-bit)
let n: int = 100;
let f: float = 3.14;
let b: bool = true;
let s: string = "text";  // Immutable UTF-8
let c: char = '🎉';

// Optional types (key to NULL safety)
let value: string? = nil;
let result = value || "default";  // Unwrap or default
let length = value?.len();  // Safe chaining (returns nil if value is nil)
println(value!);  // Unwrap (panics if nil - use sparingly)

// Collections
let array = [1, 2, 3];
let map = {"key": "value"};
let empty: [int] = [];

Error Handling Pattern

// Declare function can throw
fn divide(a: int, b: int): int throws {
    if (b == 0) {
        throw "Division by zero";
    }
    return a / b;
}

// Handle errors
let result = try? divide(10, 0);  // Returns int? (nil on error)
let result = try divide(10, 2);   // Propagate error up
let result = try! divide(10, 2);  // Panic on error

// Do-catch block
do {
    let r = try divide(10, 0);
} catch (e) {
    println(e.error());
}

Control Flow Patterns

// If-let for optionals
if (let value = optional) {
    println(value);  // value is unwrapped here
}

// Let-else for early returns
let value = optional else {
    return;
};
// value is unwrapped here

// Switch with type matching
switch (let v = value.(type)) {
    case int:
        println("integer");
    case string:
        println("string");
    default:
        println("other");
}

// For loops
for (let i in 0..10) {  // Range
    println(`${i}`);
}

for (let item in array) {  // Array
    println(item);
}

for (let k, v in map) {  // Map
    println(`${k}: ${v}`);
}

Concurrency Basics

use std.time;

fn main() throws {
    let ch = channel::<int>();

    // Spawn concurrent task (not parallel - single thread)
    spawn {
        time.sleep(0.1.seconds());
        try! ch.send(42);
    }

    let result = try ch.recv();
    println(`${result}`);
}

Worker Pattern

use std.worker.Worker;

fn main() throws {
    // Create worker with closure
    let worker = try Worker.create(|worker| {
        let msg = try worker.recv::<string>()!;
        try worker.send(msg.to_uppercase());
    });

    try worker.send("hello");
    let response = try worker.recv::<string>();
    println(response);  // "HELLO"
}

Navi Stream Integration

use nvs.macd;  // Import .nvs file as module

fn main() throws {
    // Create instance of NVS indicator
    let indicator = macd.new();

    // Execute with market data
    indicator.execute(
        time: 1234567890,
        open: 100.0,
        high: 105.0,
        low: 99.0,
        close: 103.0,
        volume: 1000.0,
        turnover: 100000.0
    );

    // Access exported variables
    println(`hist=${indicator.hist:?}`);
    println(`signal=${indicator.signal:?}`);
    println(`macd=${indicator.macd:?}`);
}

Variadic Arguments

// Accept arbitrary number of arguments
fn sum(values: ..int): int {
    let total = 0;
    for (let n in values) {
        total += n;
    }
    return total;
}

sum(1, 2, 3);           // Call with multiple args
let nums = [2, 3, 4];
sum(..nums);            // Spread array
sum(1, ..nums, 5);      // Mix regular and spread

// With other parameters
fn format(prefix: string, parts: ..string): string {
    return prefix + parts.join(",");
}

The platforms on this page are catalog indications. The paths below follow tool documentation; they do not prove this skill has been run in those tools. No minimum tool version is confirmed for this listing.

3. Load the skill

After inspection, copy the complete folder into your project using one of the commands below, then open a new tool session. The command stops if a folder with the same name already exists: compare the files before replacing it.

Claude Code
test -f '.skill-downloads/navi-programming-language-expert-mm5t89c4/SKILL.md' && test -s '.skill-downloads/navi-programming-language-expert-mm5t89c4/SKILL.md' && mkdir -p '.claude/skills' && test ! -e '.claude/skills/navi' && cp -R '.skill-downloads/navi-programming-language-expert-mm5t89c4' '.claude/skills/navi'

OpenSkills

OpenSkills must already be installed. The local install/read procedure is checked with OpenSkills 1.5.0, which requires Node.js ≥ 20.6.0. Catalog slugs are not resolved automatically.

Official OpenSkills installation
openskills install './.skill-downloads/navi-programming-language-expert-mm5t89c4'

openskills read 'navi-programming-language-expert-mm5t89c4'

Reading should display the installed file content and its base directory. It does not run the skill or install its dependencies.

For an agent that reads AGENTS.md, then sync the index. This command changes AGENTS.md: review the diff before using it.

openskills sync

Manual method or another tool: attach SKILL.md to a conversation, or open it in an agent that can read files. Include any required supporting resources. No universal folder is recognized by every tool.

4. Try a first task

Use a short, synthetic input: an API endpoint, a small document or an interface brief. In a new conversation, attach the file or give the agent its path, then adapt this request:

Read .skill-downloads/navi-programming-language-expert-mm5t89c4/SKILL.md and apply its instructions to this example: [describe a test input]. Identify any missing files, dependencies or access. Produce the result requested by the skill without inventing data or running unreviewed scripts.

Expected result: output matching the skill instructions, or a precise list of missing prerequisites. A read confirmation alone does not validate a first use. If an external resource is unavailable, that path remains untested.

Related skills