
M14 Mental Model
Reframe Java-style reference thinking into Rust ownership, borrowing, and lifetimes before writing or reviewing Rust code.
Overview
M14 Mental Model is a journey-wide agent skill that teaches ownership, borrowing, and lifetimes—usable whenever a solo builder needs to reason about Rust memory before committing to an implementation.
Install
npx skills add https://github.com/zhanghandong/rust-skills --skill m14-mental-modelWhat is this skill?
- Three core models: ownership as single-owner cleanup, borrowing as temporary access, lifetimes as validity scopes
- Concrete snippets for String ownership, &String borrows, and explicit 'a lifetime on longest
- Contrasts Rust with Java/C# everything-is-a-reference habits to reduce fight-the-borrow-checker loops
- Structured as repeatable perspective shifts for debugging and API design
- 3 core mental models: ownership, borrowing, lifetimes
Adoption & trust: 713 installs on skills.sh; 1.2k GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
You keep writing Rust like Java with references and the borrow checker blocks you without a clear mental map of who owns what.
Who is it for?
Solo builders learning Rust or jumping from GC languages who want consistent agent guidance on memory rules.
Skip if: Pure frontend CSS work, or experts who only need crate-specific API docs without conceptual reframing.
When should I use this skill?
Before writing or refactoring Rust when ownership, borrows, or lifetimes are unclear or you are coming from GC languages.
What do I get? / Deliverables
You and your agent align on ownership, borrows, and lifetime bounds so APIs and fixes compile with fewer guessing cycles.
- Shared ownership/borrow/lifetime framing for the current task
- Safer function signatures and refactor direction
Recommended Skills
Journey fit
Useful at every journey phase - explore requirements and options before committing to a direction.
Where it fits
Decide whether Rust’s ownership model is acceptable for your latency-sensitive service before choosing the stack.
Design function signatures that borrow instead of cloning large Strings across layers.
Review a PR where returned references might outlive temporary data and apply lifetime reasoning.
Diagnose a production panic or compile error caused by moving ownership twice through a refactor.
Spike a small Rust CLI prototype without fighting the borrow checker on every line.
How it compares
Use instead of ad-hoc “just clone everything” prompts; this is conceptual Rust methodology, not a test runner or linter skill.
Common Questions / FAQ
Who is m14-mental-model for?
Solo and indie developers building Rust services or CLIs who need ownership and lifetime intuition while pair-programming with an agent.
When should I use m14-mental-model?
Use it journey-wide: in Build (backend) before designing structs and functions, in Ship (review) when references look suspicious, in Operate (iterate) when debugging use-after-move errors, and in Idea (discover) when deciding if Rust fits your performance goals.
Is m14-mental-model safe to install?
Review the Security Audits panel on this Prism page; the skill is documentation-only with no runtime permissions beyond what your agent already has.
SKILL.md
READMESKILL.md - M14 Mental Model
# Thinking in Rust: Mental Models ## Core Mental Models ### 1. Ownership as Resource Management ``` Traditional: "Who has a pointer to this data?" Rust: "Who OWNS this data and is responsible for freeing it?" ``` Key insight: Every value has exactly one owner. When the owner goes out of scope, the value is dropped. ```rust { let s = String::from("hello"); // s owns the String // use s... } // s goes out of scope, String is dropped (memory freed) ``` ### 2. Borrowing as Temporary Access ``` Traditional: "I'll just read from this pointer" Rust: "I'm borrowing this value, owner still responsible for it" ``` Key insight: Borrows are like library books - you can read them, but must return them. ```rust fn print_length(s: &String) { // borrows s println!("{}", s.len()); } // borrow ends, caller still owns s let my_string = String::from("hello"); print_length(&my_string); // lend to function println!("{}", my_string); // still have it ``` ### 3. Lifetimes as Validity Scopes ``` Traditional: "Hope this pointer is still valid" Rust: "Compiler tracks exactly how long references are valid" ``` Key insight: A reference can't outlive the data it points to. ```rust fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { // 'a means: the returned reference is valid as long as BOTH inputs are valid if x.len() > y.len() { x } else { y } } ``` --- ## Shifting Perspectives ### From "Everything is a Reference" (Java/C#) Java mental model: ```java // Everything is implicitly a reference User user = new User("Alice"); // user is a reference List<User> users = new ArrayList<>(); users.add(user); // shares the reference user.setName("Bob"); // affects the list too! ``` Rust mental model: ```rust // Values are owned, sharing is explicit let user = User::new("Alice"); // user is owned let mut users = vec![]; users.push(user); // user moved into vec, can't use user anymore // user.set_name("Bob"); // ERROR: user was moved // If you need sharing: use std::rc::Rc; let user = Rc::new(User::new("Alice")); let user2 = Rc::clone(&user); // explicit shared ownership ``` ### From "Manual Memory Management" (C/C++) C mental model: ```c char* s = malloc(100); // ... must remember to free(s) ... // ... what if we return early? ... // ... what if an exception occurs? ... free(s); ``` Rust mental model: ```rust let s = String::with_capacity(100); // ... use s ... // No need to free - Rust drops s automatically when scope ends // Even with early returns, panics, or any control flow ``` ### From "Garbage Collection" (Go/Python) GC mental model: ```python # Create objects, GC will figure it out users = [] for name in names: users.append(User(name)) # GC runs sometime later, when it feels like it ``` Rust mental model: ```rust let users: Vec<User> = names .iter() .map(|name| User::new(name)) .collect(); // Memory is freed EXACTLY when users goes out of scope // Deterministic, no GC pauses, no unpredictable memory usage ``` --- ## Key Questions to Ask ### When Designing Functions 1. **Does this function need to own the data, or just read it?** - Need to keep it: take ownership (`fn process(data: Vec<T>)`) - Just reading: borrow (`fn process(data: &[T])`) - Need to modify: mutable borrow (`fn process(data: &mut Vec<T>)`) 2. **Does the return value contain references to inputs?** - Yes: need lifetime annotations - No: lifetime elision usually works ### When Designing Structs 1. **Should this struct own its data or reference it?** - Long-lived, independent: own (`name: String`) - Short-lived view: reference (`name: &'a str`) 2. **Do multiple parts need to access the same data?** - Single-threaded: `Rc<T>` or `Rc<RefCell<T>>` - Multi-threaded: `Arc<T>` or `Arc<Mutex<T>>` ### When Hitting Borrow Checker Errors 1. **Am I trying to use a value after moving it?** - Clone it, borrow it, or restructure the code 2. **Am I trying to have multiple mutab