skills/flix/SKILL.md
This skill should be used when the user asks to "write Flix code", "translate to Flix", "set up a Flix project", "fix Flix compiler errors", "add Java interop in Flix", or when encountering .flix files or flix.toml. Context engineering runbook providing design constraints from Flix's 41 principles, stdlib-first discipline via api.flix.dev, and anti-hallucination guidance for a language with sparse training data.
npx skillsauth add synapseradio/ai-skills flixInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This is a context engineering runbook, not a Flix manual. Flix has sparse training data in LLM corpora — Scala/Haskell/Java instincts will produce code that does not compile. Load official docs before writing code.
Before writing any non-trivial Flix code:
references/design-principles.md — focus on HIGH-delta principles. Skip compiler message principles (26–31).https://api.flix.dev/ for modules you need.https://doc.flix.dev/interoperability.htmlConditional loading — load only what the task requires:
| Situation | Load | Do NOT load |
|-----------|------|-------------|
| Writing effect-heavy code | references/effect-system.md | translation references |
| Calling Java from Flix | references/interop-patterns.md | translation references |
| Need a stdlib function | references/stdlib-map.md | effect-system, interop |
| Translating from TypeScript | references/translate-typescript.md | other translate-.md files |
| Translating from Python | references/translate-python.md | other translate-.md files |
| Translating from Rust | references/translate-rust.md | other translate-*.md files |
| Simple List/Map/Option task | Nothing extra — SKILL.md is sufficient | all references |
This is not optional. Flix has too few training examples for confident generation without loading context first.
Before importing any Java class, check the Flix standard library at https://api.flix.dev/.
The stdlib covers strings, collections (List, Map, Set, Vector), Option/Result, file I/O, environment variables, concurrency (channels, spawn), regex, and more. Check it first because:
\ IOunsafe blocks| Need this? | Check this module | Instead of Java... |
|------------|-------------------|-------------------|
| String split/join/pad/trim | String | java.lang.String |
| Regex matching | Regex (literal regex"...") | java.util.regex.Pattern |
| List/Set/Map operations | List, Set, Map | java.util.ArrayList, HashSet, HashMap |
| Indexed access | Vector (persistent) or Array (mutable) | int[], ArrayList |
| Mutable key-value | MutMap (region-scoped) | java.util.HashMap |
| Option chaining | Option | java.util.Optional |
| Error propagation | Result | try/catch with checked exceptions |
| File reading | FileRead effect | java.io.File, Files.readAllLines() |
| File writing | FileWrite effect | java.io.FileWriter, Files.write() |
| Environment variables | Env effect | System.getenv() |
| CLI arguments | Env.getArgs() | String[] args |
| System paths (home, tmp, cwd) | Env effect | System.getProperty(...) |
| Channels / concurrency | Channel + spawn keyword | BlockingQueue, ExecutorService |
| Number parsing | Int32.fromString / Float64.fromString | Integer.parseInt |
| Char classification | Char | Character.isDigit() |
| Sorting | List.sort / Array.sort | Collections.sort() |
| Printing | println (Prelude) | System.out.println() |
| Exception wrapping | Result.tryCatch | try/catch blocks |
Full task-to-module map with key functions: references/stdlib-map.md
These have no stdlib equivalent — Java interop is appropriate:
java.time.*)Exec effect covers)Before choosing an approach, ask:
api.flix.dev first. Java interop only for genuine gaps (HTTP, JSON, crypto, datetime).Map/List/Set. Use region-scoped mutation (MutMap, Array) only when building a result imperatively, then toImmutable.Result for errors callers handle locally. Algebraic effects for swappable capabilities (DB, config, logging).substr = "foo").&&, ||, ! — use and, or, notnull — use Option[t]use Foo.*) — name each import. for record field access — use # (record#field);api.flix.devunsafe on expressions that actually perform I/O_ prefixThese are the principles that most affect how you write code. Violating any of these produces a compile error, not a warning.
Boolean operators are not, and, or. The symbols !, &&, || are not boolean operators.
// WRONG — will not parse
if (x && y || !z) ...
// CORRECT
if (x and y or not z) ...
Re-declaring a variable name in any nested scope is a compile error.
// WRONG — compile error
let x = 1
let x = x + 1
// CORRECT
let x = 1
let y = x + 1
null does not exist in Flix types. Use Option[t] for absent values. Null only appears at the Java interop boundary and must be checked there.
No widening, auto-boxing, or implicit conversion. All type conversions are explicit.
A statement expression e1; e2 requires e1 to be impure and of type Unit. Pure expressions or non-Unit expressions in statement position are compile errors. You cannot discard a return value silently.
Every stdlib function takes its subject as the last argument:
List.map(f, xs) // list is last
String.contains(substr = "foo", s) // string is last
Map.get(k, m) // map is last
This enables pipeline composition with |>:
xs |> List.filter(x -> x > 0) |> List.map(x -> x * 2)
Functions cannot share a name with different argument types/counts. Overloading is only through type classes.
All stdlib functions are total. List.head returns Option[a], not a bare element. There is no partial head, tail, or !!.
All declarations are private. Use pub for public visibility.
Every function has a tracked effect in its type. Pure functions cannot perform IO. Adding println inside a pure function changes its effect type and breaks callers.
// Pure — no effect annotation
def add(x: Int32, y: Int32): Int32 = x + y
// Impure — must declare effect
def greet(name: String): Unit \ IO = println("Hello ${name}")
use Foo.* is forbidden_ to mark intentionally unused! (Principle 38) — Array.sort returns new; Array.sort! mutatesString.contains(substr = "a", s) not positionalFull list of all 41 principles with delta ratings: references/design-principles.md
| I need to... | Fetch this |
|-------------|-----------|
| Understand effects and purity | https://doc.flix.dev/effect-system.html |
| Write algebraic effect handlers | https://doc.flix.dev/effects-and-handlers.html |
| See primitive effect list (IO, Net, FsRead...) | https://doc.flix.dev/primitive-effects.html |
| Call Java code / use JVM libraries | https://doc.flix.dev/interoperability.html |
| Create Java objects from Flix | https://doc.flix.dev/creating-objects.html |
| Call Java methods (instance, static, varargs) | https://doc.flix.dev/calling-methods.html |
| Pattern match on types or values | https://doc.flix.dev/pattern-matching.html |
| Set up a project / manage deps | https://doc.flix.dev/build.html |
| Add Flix or Maven dependencies | https://doc.flix.dev/packages.html |
| Organize code into modules | https://doc.flix.dev/modules.html |
| Write functions (HOF, currying, pipes) | https://doc.flix.dev/functions.html |
| Use Datalog / logic programming | https://doc.flix.dev/functional-predicates.html |
| Understand type casts | https://doc.flix.dev/type-casts.html |
| Check operator precedence | https://doc.flix.dev/appendix.html |
| Check stdlib API for any module | https://api.flix.dev/ |
| Read the design paper (Onward! 2022) | https://flix.dev/paper/onward2022.pdf |
When a navigation entry is relevant, actually fetch and read the page before writing code.
| From (Scala/Haskell/Java) | In Flix | Key difference |
|---------------------------|---------|----------------|
| null | Option[t] | No null at all — Option everywhere |
| && / || / ! | and / or / not | Keyword-based, not symbolic |
| try/catch (exceptions) | Result + algebraic effects | eff / run ... with handler for control flow |
| val x = ...; val x = ... | Compile error | No variable shadowing permitted |
| implicit conversions | Not available | No implicit coercions of any kind |
| import pkg._ (wildcard) | use Mod.{a, b} | Explicit imports only |
| interface/trait | trait with eff support | Traits can declare associated effects |
| for/do notation (monadic) | Direct style | No monadic wrapping — use effects |
| head / tail (partial) | List.head → Option | All stdlib functions are total |
| Unit returned implicitly | Compile error | Pure non-Unit expressions in statement position rejected |
| list.map(f) (subject-first) | List.map(f, list) | Subject-last enables \|> pipelines |
| x.sort() (mutation) | Array.sort! vs Array.sort | ! suffix marks destructive operations |
| static fields | Not available | No global state — thread everything from main |
| obj.field (dot access) | record#field (hash access) | # is the record label accessor, not . |
| f"Hello {name}" / `Hello ${name}` | "Hello ${name}" | ${} in double-quoted strings; no format prefix |
| Custom annotations | Not available | Annotations are built-in only |
| Wildcard type params | typematch dispatch | Compile-time type dispatch, not runtime erasure |
Three kinds of effects, each with different properties:
| Kind | Defined by | Handleable? | Example |
|------|-----------|-------------|---------|
| Primitive | Compiler (maps Java classes) | No — viral | IO, Net, FsRead, FsWrite, Env, Exec, NonDet, Sys, Chan |
| Algebraic | User (eff keyword) | Yes — scoped | eff Ask { def ask(): String } |
| Heap | Region blocks | Yes — scoped | region rc { let s = MutSet.empty(rc) } |
No effect annotation = pure. The \ separator declares effects:
def pure(): Int32 = 42
def impure(): Unit \ IO = println("hello")
def multi(): Unit \ {IO, Net} = ...
def polymorphic(f: a -> b \ ef): List[b] \ ef = ...
Deep dive on effects: references/effect-system.md
flix init # scaffold project
flix check # type-check only (fast)
flix run # compile and run main
flix test # run @Test functions
flix build-fatjar # standalone JAR with all deps
Manifest (flix.toml):
[package]
name = "my-project"
version = "0.1.0"
flix = "0.54.0"
[dependencies]
"github:owner/repo" = "1.0.0"
[mvn-dependencies]
"org.example:artifact" = "1.2.3"
Project layout: src/Main.flix + test/TestMain.flix + flix.toml
When translating from a language you know well, load the appropriate reference for side-by-side examples showing how familiar patterns map to Flix:
| Coming from... | Load this |
|----------------|-----------|
| TypeScript / Effect-TS | references/translate-typescript.md |
| Python | references/translate-python.md |
| Rust | references/translate-rust.md |
Each reference provides paired examples in XML format covering common tasks — error handling, collections, concurrency, I/O — with observations about how the languages approach the same problem differently.
Load these when you need deeper guidance on a specific topic:
| File | Load when... |
|------|-------------|
| references/design-principles.md | You need to understand why Flix does something — full table of 6 values + 41 principles |
| references/effect-system.md | Writing effect-heavy code — eff/handler syntax, purity tracking, direct-style patterns |
| references/interop-patterns.md | Calling Java from Flix — import syntax, null handling, type mapping, unsafe blocks |
| references/stdlib-map.md | Finding the right stdlib function — task-to-module map organized by what agents commonly need |
| references/translate-typescript.md | Translating TypeScript/Effect-TS patterns to Flix |
| references/translate-python.md | Translating Python patterns to Flix |
| references/translate-rust.md | Translating Rust patterns to Flix |
| You see... | Likely cause | Fix |
|-----------|-------------|-----|
| "Unexpected token &&" | Used symbolic boolean operator | Replace with and/or/not |
| "Duplicate variable" | Variable shadowing | Use a different variable name |
| "Non-pure expression in statement position" | Discarded a pure value with ; | Bind to _ or remove the expression |
| "Unused variable" | Let-binding never referenced | Prefix with _ or remove |
| "Type mismatch: expected X, found Y" | Implicit coercion attempted | Add explicit conversion |
| "Unexpected field access ." | Used dot instead of hash | Use record#field |
| "Unable to resolve" | Wildcard import or missing use | Add explicit use Mod.{name} |
After loading this skill, verify:
and/or/not, not &&/||/!# (not .) — record#field"text ${expr}" syntaxtools
Open the possibility space through curiosity-driven questioning
tools
Interactive tutoring that adapts to your pace
data-ai
Trace justification chains to bedrock
tools
Follow reasoning step-by-step