Command Line in EK9
This last section will discuss the command line options of the reference implementation of the compiler.
From a command prompt; just type ek9 someSource.ek9 for source to be compiled and executed.
If all you have is a single source file and want to execute it - that's it!
But, if your ek9 source file has the 'execute' bit set on Linux, Unix and MacOs and the 'ek9' command is on your
PATH, you can just type ./someSource.ek9 and the 'shebang of #!ek9 will trigger the use of the ek9 command.
Actually the EK9 compiler can do quite a bit more than just compile source code. Read the section on packaging for when you have a few sources files or thousands.
Is it a build system then?
Not quite; is probably the right answer. If you are doing a pure EK9 development then it will get you a very long way. It is designed to be used by other build systems, CI/CD pipelines and to fit into a larger build pipeline. For simple small/medium development it will probably suffice.
Can it be used with other build systems
The EK9 compiler has been designed to be usable in modern build pipelines either from other software like
So it has a number of options that don't actually compile code, but facilitate versioning and packaging.
When used with the '-ls' flag it can also be used as a language server with code editors like IntelliJ, Vim, Eclipse and VSCode. There is an extension for VSCode that can use EK9 in this mode, it also includes syntax highlighting and code snippets.
Why add all those options in?
Please read the introduction for the logic of this. These are the basic
operations you need to be able to produce and manage modern software.
Developing software now goes way beyond just compilation. The very nature of software delivery has undergone
enormous change. Building very large monolithic applications must be avoided if possible.
Packaging, version management and deployment provision are all critical aspects of creating modular software now. But also linking parts together as separate runnable modules with very specific and defined interfaces is the way forward.
Command line application
The reference implementation of the compiler has a wide range of options for very specific purposes, these are detailed below. To just run a program and have it automatically compiled see running programs.
By just running the ek9 (with no source file) like this below you will see the following options.
- $ ek9 ↵
- Usage: ek9 <options>
- where possible options include:
- ...
- filename.ek9 - the main file to work with
- -r Program to run (if EK9 file as more than one)
Options
There are a number of options that are related and these are explained in relation to each other.
General
-v Verbose mode. Outputs detailed information about what the compiler is doing during each phase of compilation.
-V Shows the version number of the compiler itself.
-dv Debug verbose mode. Produces internal debug information during compilation, including phase timings, symbol table dumps, and intermediate results. Primarily useful for compiler developers diagnosing issues in the compilation pipeline.
-di DI/AOP analysis - outputs a compact injection wiring map showing all application registrations, injection sites, and aspect proxies. Combine with -E3 for full detail including wiring map, aspect method coverage, and structured guidance.
-Up Check for a newer version of the EK9 compiler and upgrade if available. Downloads and installs the latest version, replacing the current installation.
-h A general help message for all the options available.
-h Exxxx Show the full explanation for a specific error code. For example, ek9 -h E50001 shows diagnosis, fix actions, examples, and related error codes for "not resolved" errors.
-h <TypeName> Show the full API for a built-in type, including constructors, methods, and operators. For example, ek9 -h String, ek9 -h List, ek9 -h Dict.
-H List all available help keywords categorized by topic. Use this to browse what types, keywords, and error codes have help available.
-Ep <path> Load an alternative message pack (zip file) for error explanations and DI guidance. Messages in the pack override built-in messages; error codes not in the pack fall back to the defaults. This enables researchers to experiment with different error message styles without modifying the compiler. Can be combined with -h Exxxx or -E3 to see the overridden messages.
-e <name>=<value> Define an environment variable,
for example user=Steve,
or user=\'Steve Limb\' if you must have spaces.
-T target architecture - defaults to 'java' if not specified (but see EK9_TARGET below) - actually Java the only architecture supported at present!
Also the environment variable EK9_TARGET can be used in place of -T. The -T optional will override the environment variable EK9_TARGET if used. This environment variable has been introduced so that it is not necessary to provide the command line parameter all the time.
Environment Variables
EK9 respects the following environment variables for configuration. These complement the command line flags and provide defaults that persist across invocations.
Installation and Target
EK9_HOME - Directory containing the EK9 compiler JAR (ek9c-jar-with-dependencies.jar). If not set, the wrapper looks in the same directory as the ek9 executable. Useful for switching between compiler versions.
Example: export EK9_HOME=/opt/ek9/0.0.2
Memory Configuration
EK9_COMPILER_MEMORY - Sets the maximum heap size for the EK9 compiler itself. Defaults to -Xmx512m if not set. Useful for large projects or when running multiple compilations in parallel.
Example: export EK9_COMPILER_MEMORY="-Xmx1024m"
EK9_APPLICATION_MEMORY - Sets the maximum heap size for compiled EK9 applications when running them. Defaults to -Xmx512m if not set. Adjust this based on your application's memory requirements.
Example: export EK9_APPLICATION_MEMORY="-Xmx2048m"
Terminal Output Control
EK9 auto-detects terminal capabilities (colors, Unicode, emoji) using standard environment variables. You can override detection with these:
EK9_PLAIN_TEXT - When set (to any value), forces all output to plain ASCII text with no colors, no Unicode box-drawing characters, and no emoji. Useful for piping output to files or for terminals with limited capabilities.
Example: export EK9_PLAIN_TEXT=1
NO_COLOR - When set, disables color output. Follows the no-color.org convention used by many CLI tools. Unicode and emoji are still used if the terminal supports them.
FORCE_COLOR - When set, forces color output even if the terminal is not detected as color-capable. Useful in CI/CD pipelines that support ANSI colors but don't set standard TERM values.
Language Server
The compiler can be used as a Language Server, in this mode it does not produce an executable as an output; but it does complete the 'front end' phase of compilation (up to PRE_IR_CHECKS) and provides real-time diagnostics to your editor.
-ls Use compiler as a 'Language Server' only with stdin/stdout as the protocol channel.
-lsh This flag will configure the EK9 language server so that it provides additional EK9 language hover help. This includes hover help for 'operators' such as ':= for example. So is very useful when first using EK9, the hover help also includes hyperlinks to the appropriate sections on this site.
Supported Capabilities
The EK9 language server provides the following capabilities:
- Diagnostics - Real-time compilation errors and warnings as you type. The entire workspace is recompiled when files are opened or changed, providing immediate feedback.
- Hover - Hover over any symbol to see its type information. With -lsh enabled, hovering over EK9 keywords and operators also shows language help with hyperlinks to documentation.
- Completion - Tab completion for EK9 keywords and built-in type names. Uses fuzzy matching so partial input like sw suggests switch.
- Go to Definition - Navigate from a symbol usage to its definition.
- Go to Declaration - Navigate to where a symbol is declared.
- Find References - Find all usages of a symbol across the workspace.
Editor Integration
There is an EK9 VSCode Extension available that provides syntax highlighting, code snippets, and language server integration. To use it:
- Install the EK9 extension from the VSCode marketplace
- Ensure the ek9 command is on your PATH
- Open a folder containing .ek9 files
The language server can also be used with any editor that supports LSP, including IntelliJ, Vim, Eclipse, and Neovim. Configure your editor to launch ek9 -ls (or ek9 -ls -lsh for enhanced hover help) as the language server command for .ek9 files.
MCP Server (Model Context Protocol)
The compiler can also run as an MCP server, providing AI coding assistants (such as Claude Code, Cursor, and other MCP-compatible tools) with direct programmatic access to the EK9 compiler's capabilities. This enables AI assistants to compile code, look up error explanations, search the Q&A knowledge base, format source code, and inspect symbols — all without leaving the AI conversation.
-mcp Run the compiler as an MCP server using stdin/stdout as the JSON-RPC transport.
Available Tools
The MCP server exposes seven tools that AI assistants can call:
- version - Returns the compiler version. No parameters required. Useful for verifying the MCP server is responsive.
- help - Get keyword or type help. Pass
keyword: "list"to see all available keywords, or a specific keyword/type name (e.g.,keyword: "String",keyword: "switch") to see its full API or usage help. Equivalent to ek9 -h <keyword>. - explain_error - Get a rich explanation for an error code (e.g.,
errorCode: "E05030"). Returns diagnosis, common causes, fix actions, and examples. Equivalent to ek9 -h Exxxx. - paradigm - Get EK9's paradigm summary: 11 key design decisions that differ from mainstream languages. No parameters required. Equivalent to ek9 -h -E4.
- ask - Search the Q&A knowledge base with a natural language query. Parameters:
query(required),mode("summary","detailed", or"migration"),maxResults(default 3). Returns matched questions with answers and compilable code examples. - compile - Compile the EK9 workspace. Parameters:
phase(compilation phase to target, default"PRE_IR_CHECKS"),errorLevel(0–3, default 3 for rich AI explanations),devBuild(include dev code, default false). Returns diagnostics with line:column locations and detailed explanations. - format - Format EK9 source code to canonical style. Pass the source code as a string and receive the formatted result. Equivalent to the -f formatting pipeline.
Available Resources
The MCP server also exposes two resources that AI assistants can read:
- ek9://diagnostics - Compilation diagnostics from the last compile tool call.
Returns a JSON array of diagnostic objects with file, line, column, severity, error code, and message.
Can be filtered by filename (e.g.,
ek9://diagnostics/myfile.ek9). - ek9://symbols/{moduleName} - Symbol table for a compiled module. Returns a JSON array of symbol objects with name, kind (CLASS, RECORD, TRAIT, FUNCTION, etc.), and type information. Requires a prior compile call.
Configuration
To use EK9 as an MCP server with an AI coding assistant, configure the assistant to launch the EK9 compiler with the -mcp flag. For example, in a Claude Code MCP configuration:
- // .mcp.json or equivalent configuration
- {
- "mcpServers": {
- "ek9": {
- "command": "ek9",
- "args": ["-mcp"]
- }
- }
- }
The MCP server uses newline-delimited JSON-RPC 2.0 over stdin/stdout. It supports the standard
MCP lifecycle: initialize, initialized, tools/list,
tools/call, resources/list, resources/read,
shutdown, and exit.
Tools like help, paradigm, explain_error, and ask work without any compilation — they provide offline reference information. The compile tool triggers a full workspace compilation and caches results for subsequent diagnostics and symbols resource reads.
Q&A Knowledge Base
EK9 includes a built-in Q&A knowledge base covering language features, design decisions, and migration guidance from other languages. This is useful for both developers learning EK9 and AI coding assistants that need EK9 context.
-q List all Q&A entries organized by category. Provides a browsable overview of all available questions and answers.
-q <words> Search for Q&A entries matching the given words. Returns a concise summary with a compilable code example. Uses fuzzy matching with synonym resolution so you don't need exact wording.
-q <number> Fetch a specific Q&A entry by its ID number. For example, ek9 -q 23 retrieves the Q&A about basic types.
-qd <words> Detail Q&A search. Returns the full answer with all sections and a compilable code example. Use when you need comprehensive information beyond the summary.
-qm <words> Migration-focused Q&A search. Returns the summary and a migration context section comparing how the feature works in Java, Python, Rust, Go, Kotlin, and other languages. Designed for developers transitioning to EK9 from another language.
-qdm <words> Full detail with migration context. Combines -qd and -qm to show the complete answer plus per-language migration comparisons.
-Q Dump all Q&A training data as JSONL (JSON Lines) format. Each line is a complete JSON object with question, answer, code example, keywords, and migration context. Designed for fine-tuning LLMs on EK9 language knowledge.
- $ ek9 -q // List all Q&A by category
- $ ek9 -q guard variables // Summary + code example
- $ ek9 -qd guard variables // Full detail + code example
- $ ek9 -q 50 // Get Q&A #50 directly
- $ ek9 -qm generics templates // Summary + migration context
- $ ek9 -qdm generics templates // Full detail + migration context
- $ ek9 -Q > training.jsonl // Export for LLM training
Compilation
There are a number of different options to control compilation, this gives quite fine-grained control over full builds versus incremental builds. What constitutes the source files is described in small applications, medium applications, large applications and use of libraries.
-c Incremental compile; but don't run. Only source files that have changed get recompiled.
-cg As above; incremental compile but with debugging information.
-cd As above; incremental compile but with all dev code and debugging information.
-Cl Clean all, including dependencies.
-C Full recompile; but don't run. All source files are recompiled even if they have not changed.
-Cg As above; full recompile but with debugging information.
-Cd As above; full recompile but with all dev code and debugging information.
Compile Without Linking
These options compile source code but skip the final linking step that creates an executable. Useful for checking compilation without producing a runnable artifact, or when integrating with external build systems that handle linking separately.
-ch Incremental compile, no link. Only changed sources are recompiled; no executable is produced.
-cdh As above; incremental compile with all dev code, no link.
-Ch Full recompile, no link. All sources recompiled; no executable is produced.
-Cdh As above; full recompile with all dev code, no link.
Phased Compilation
These options compile up to a specific compiler phase number and then stop. Useful for debugging the compiler pipeline or inspecting intermediate results.
-Cp <N> Full recompile; compile up to phase N only. For example, ek9 -Cp 10 file.ek9 compiles up to and including phase 10 (IR generation).
-Cdp <N> As above; full recompile with all dev code, compile up to phase N only.
Dev Code
The idea of dev code is the concept of defining some source code that is not really part of your
program/application or library; but is code used as an example or for testing.
It can be more than just unit test code, it could be a set of worked examples, templates, how-tos.
Basically it can be anything that another developer might find useful that is not part of the main functionality your software provides. So by default a user of your library (if that's what you are creating) would not use any of the code in your /dev directory in production use. But would really value real examples and tests that you have provided to show how your library can and should be used.
So it's best to make these /dev code examples short, tight to the point and easy to snip to enable the developer using your library to take that snip and rework it into their application.
So rather than the developer searching the internet for examples of how to use the library, include real examples and tests to show and help that developer get going.
Integration/Unit tests, any programs that start with 'test' in the /dev directory or subdirectories are considered integration/unit tests (see -t optional later).
Error Verbosity Levels
EK9 provides cumulative error verbosity levels for enhanced error diagnostics. Each level includes all features from lower levels:
-E0 Minimal error format (default). Compact single-line error messages suitable for scripted processing and CI/CD pipelines.
-E1 Visual errors. Rust/Elm-style error display with source code snippets and caret markers (^^^^^) showing exact error locations. Provides clear visual context for understanding where errors occur.
-E2 Visual + Suggestions. Adds "Did you mean?" suggestions for typos using fuzzy string matching (Levenshtein distance). Shows up to 3 similar names when a symbol, method, or type cannot be resolved. Particularly useful for catching spelling mistakes.
-E3 Rich mode. Full AI-assisted error explanations with detailed guidance on how to fix the issue. Includes hyperlinks to relevant documentation on ek9lang.org. Recommended for learning EK9 or debugging complex type errors.
-E4 Paradigm summary. Outputs a concise summary of EK9's key design decisions
and built-in capabilities that differ from mainstream languages. Covers: no break/continue/return,
tri-state semantics, closed types, automatic operators for enumerations and records, naming
conventions, complexity limits, and assignment operators. Use ek9 -h -E4 for a quick
overview, or include with compilation to see the summary alongside errors.
-E5 Full AI bootstrap. Everything from -E4 plus a complete dump of
forAI.json — a structured reference covering all EK9 language features, excluded
keywords, operators, constructs, and design rationale. Use ek9 -h -E5 once to learn
EK9, then switch to -E3 for ongoing development. The JSON dump is approximately 107KB
and is designed for AI coding assistants that need comprehensive language context.
Example Output
The following shows how the same error appears at different verbosity levels. In terminals that support colors, error text appears in red, code references in cyan, and hints in green. Emoji icons (â đĄ đ§ đ đ) are shown in modern terminals, with Unicode/ASCII fallbacks for others.
-E0 (Minimal):
EK9 : Error : E50001: 'coutn' on line 15 position 16: 'coutn': not resolved
See: https://ek9.io/errors.html#E50001
-E1 (Visual): Rust-style display with source code and caret markers.
EK9 : â error :[E50001]: 'coutn' on line 15 position 16: 'coutn': not resolved
âââļ workarea.ek9:15:17
â
15 â result <- coutn + 1
â ^^^^^ 'coutn'
â
ââ đ See: https://ek9.io/errors.html#E50001
-E2 (Visual + Suggestions): Adds "Did you mean?" fuzzy matching with location info.
EK9 : â error :[E50001]: 'coutn' on line 15 position 16: 'coutn': not resolved
âââļ workarea.ek9:15:17
â
15 â result <- coutn + 1
â ^^^^^ 'coutn'
â
ââ đĄ help: did you mean 'count as Integer'?
â âââļ defined at line 13
ââ đ See: https://ek9.io/errors.html#E50001
-E3 (Verbose): Full explanation box with structured guidance sections.
EK9 : â error :[E50001]: 'coutn' on line 15 position 16: 'coutn': not resolved
âââļ workarea.ek9:15:17
â
15 â result <- coutn + 1
â ^^^^^ 'coutn'
â
ââ đĄ help: did you mean 'count as Integer'?
â âââļ defined at line 13
ââ đ See: https://ek9.io/errors.html#E50001
ââ âšī¸ EXPLANATION
â
â COMMON CAUSES:
â - Typo in identifier name
â - Variable not declared in scope
â - Missing import/reference statement
â - Using before definition
â đ§ TO FIX:
â - Check spelling, add reference, or declare variable
â DISTINCTION:
â - E50001 is for identifiers/variables
â - E50010 is for types
â - E50060 is for methods
âââ
Source Formatting
EK9 includes a built-in source code formatter that enforces canonical style (2-space indentation, consistent spacing, ordered declarations). The formatter is safe — if formatting fails for any reason, the original file is preserved unchanged.
-f Format a single EK9 source file to canonical style. The file must parse successfully before formatting can be applied.
-F Format all EK9 source files in the project. Applies the same canonical formatting to every .ek9 file discovered in the project.
-ff Force format a single file. Attempts to fix common issues that prevent parsing (tabs, odd indentation, missing shebang, keyword typos) before applying canonical formatting. Use this when -f fails due to indentation problems.
-fF Force format all project files. Applies the same force formatting to every .ek9 file in the project.
- $ ek9 -f myfile.ek9 // Format single file
- $ ek9 -F myfile.ek9 // Format all project files
- $ ek9 -ff myfile.ek9 // Force format (fixes tabs, odd indent, typos)
- $ ek9 -fF myfile.ek9 // Force format all project files
The formatter applies four passes: canonical indentation from the parse tree, structural reordering (alphabetical references, declaration order), token spacing (operator alignment, line splitting), and comment re-indentation. Force mode additionally applies pre-processing to normalize tabs, insert missing shebangs, correct odd-width indentation, and fix keyword typos before formatting.
Dependencies
-Dp Resolve all dependencies, this triggers -Cl clean all first. If you have altered the EK9 source file that contains the package construct and altered the dependencies this will be automatically run. As you can see it will trigger a Clean and that will mean a full recompilation will also be required.
The resolved dependencies will be pulled down from repo.ek9lang.org validated and put in your $HOME/.ek9/lib directory and unpacked. So if you wanted to look at the examples, snips or tests the developer of that dependency provided then just look in your library! You can then lift some of those examples or snips from the dependency /dev directory into your own code and try them out.
Packaging
The packaging of the software for some form of reuse does not mean the software has to be 'open source' You can package your modules and re-use them all internally to your organisation, or even just on your own PC!
-P Package ready for deployment to artefact server/library.
You decide if the software is fit to package. I'd suggest a range of unit tests in the /dev
area of your project.
-I Install packaged software to your local library ($HOME/.ek9/lib).
-Gk Generate signing keys for deploying packages to an artefact server - only needed if publishing to a remote server.
-D Deploy packaged software to an artefact server, this triggers -P packaging first and -Gk if necessary. Note you will need to have an account on the remote server and also have your $HOME/.ek9/config and $HOME/.ek9/credentials setup for your package to be deployed.
Version Numbers
So that you can include versioning into your other processes, such as creating new branches in your source code repository, triggering new builds of the software - EK9 has a number of commands to help alter the version number for you. The package construct is essential for managing versioning of EK9 software.
-IV [major|minor|patch|build] - increment part of the release vector. EK9 will work out the next value to be used. You just decide it is major, minor, patch or just the build number to increment.
-SV major.minor.patch - force setting to specific value i.e 6.8.1-0 (always zeros build on setting). Useful when you want to create a new branch in your source code repository and need to ensure your code uses the same numbering.
-SF major.minor.patch-feature - force setting to specific value for features i.e 6.8.0-specials-0 (always zeros build on setting). As above but useful for feature branches.
-PV print out the current version i.e 6.8.1-0 or 6.8.0-specials-0 for a feature. Saves you having to grep it out!
Features
While features are not a unique concept to EK9 and are used very widely with git repositories - but they probably are worth a quick mention.
As outlined in versioning any release of software must have a unique version number. However, there are times when a large team need to work on the next release. Now the tricky bit, different groups of developers will form to work on a feature together. But there may be several features planned for this next release, and they all need to be worked on concurrently but with some form of isolation from each other.
This is where a new set of feature branches are created, each group then work on their features in a sort of semi isolated manner. All striving to get their features ready for the next main build. During this time all the members of the team working on a feature work on the same code (git enables this). But critically they also need to run full automated builds and tests of their group effort. In some cases they may even need to deploy their feature and demonstrate it to end users, product owners or parts of the testing team (or even marketing departments).
That software needs a version number so that any issues, new ideas, defects or alterations can be made. Importantly it must include some name that the teams understand i.e. the feature. That is why EK9 has a special locations in the version numbering for a feature name.
Some features never see the light of day, others are fit for purpose and get folded back into the main development branch. Others need more work and don't quite make the 'cut' for the next major version to be delivered; hence they have to go into another release scheduled later. Sometimes features are merged and refined further by merging git feature branches. EK9 supports this by enabling the version number to be manipulated in a controlled manner.
The 'run' options
These are really the options you care about, running your software. By default, if no options are given then -r (run) is assumed. But importantly if the source code has not been compiled yet; the EK9 compiler will trigger a full build - including resolving dependencies. This means you can just write (or download) some EK9 source and then 'run it'. First time though it will be checked and compiled, subsequently if nothing has been altered it will just be 'run' without recompiling.
-t or -t1 Runs all unit tests with human-readable output. This triggers a full compile with debugging information (-Cd) and forces -O0 (no optimization) to ensure accurate coverage probe-to-source mapping. Tests are discovered by finding all programs marked with the @Test directive in the /dev directory and subdirectories.
Test Output Format Options:
- -t or -t1 - Human-readable output with visual formatting (default)
- -t0 - Terse output (minimal summary for scripting and CI pass/fail checks)
- -t2 - JSON output (structured format for AI/tool integration)
- -t3 - JUnit XML output (for CI/CD integration with Jenkins, GitHub Actions, GitLab)
- -t4 - Detailed coverage output (human-readable plus detailed coverage report)
- -t5 - Verbose/full coverage (shows both covered and uncovered items in detail)
- -t6 - HTML coverage report (generates interactive .ek9/coverage/index.html with SVG charts, module breakdown, source views, search, and dark/light theme support)
Coverage Options:
- -tC - Display coverage results after test execution
When using -tC with -t or -t1, if coverage is below 80%, EK9 automatically generates a detailed coverage report to .ek9/coverage-detail.json listing all uncovered methods and branches with file:line locations. This helps developers quickly identify what needs testing. Use -t4 to force this detailed report even when coverage is above 80%.
Profiling Options:
- -tp, -t1p through -t6p â append p to any test format to enable performance profiling. Records call counts, timing, and percentile distributions (p50, p95, p99) per function.
- -t2p â JSON profiling output with full statistical metrics, ideal for AI/tool analysis
- -t6p â HTML report with flame graph, hot function table (11 columns including min/max and percentiles), and per-function profiling badges in source view
- $ ek9 -tp myapp.ek9 // Tests + profiling summary
- $ ek9 -t2p myapp.ek9 // JSON output with profiling data
- $ ek9 -t5p myapp.ek9 // Verbose coverage + profiling
- $ ek9 -t6p myapp.ek9 // Full HTML with flame graph
Profiling is additive — it does not replace coverage or test results. All three datasets (test results, coverage, profiling) are collected simultaneously. See Performance Profiling for detailed documentation including how to interpret flame graphs and hot function tables.
Tests can be grouped using @Test: "groupname" for sequential execution within a group. Ungrouped tests run in parallel using 75% of available CPU cores.
Test Filtering Options:
- -tL - List all tests without running them (respects -t0/-t1/-t2/-t3 format)
- -tg <group> - Filter tests to run only those in the specified group
The -tL flag is useful for CI/CD discovery phases and verifying test configuration. It outputs the list of discovered tests with their types, groups, and case counts without executing them.
The -tg flag enables running specific groups of tests, which is useful for: parallel execution across CI/CD runners (each runs a different group), separating slow tests from fast tests, or isolating tests that require specific resources.
- $ ek9 -tL myapp.ek9 // List all tests
- $ ek9 -tL -t2 myapp.ek9 // List tests as JSON
- $ ek9 -t -tg database myapp.ek9 // Run only database group
- $ ek9 -t2 -tg network myapp.ek9 // Run network group with JSON output
Important: The -t flag cannot be combined with optimization flags -O2 or -O3. Coverage requires unoptimized code because optimization can inline functions, eliminate dead code, and merge statements - all of which corrupt coverage accuracy. Using -t -O0 is allowed but redundant since -O0 is forced automatically.
- $ ek9 -t myapp.ek9 // OK - O0 forced automatically
- $ ek9 -t -O0 myapp.ek9 // OK - explicit but redundant
- $ ek9 -t -O2 myapp.ek9 // ERROR - optimization not allowed with tests
Compiler Fuzzing
EK9 includes a built-in grammar-based fuzzer for compiler quality assurance. See Compiler Fuzzing for full documentation including the five-strand generation strategy and interactive HTML dashboard.
- $ ek9 -fuzz 30 // 30 minutes, human-readable output
- $ ek9 -fuzz0 30 // Terse CI pass/fail
- $ ek9 -fuzz2 1440 // 24 hours, JSON for CD pipeline
- $ ek9 -fuzz6 60 // 1 hour, HTML dashboard
-s1, -s2, -s3, -s4, -s5 Strand filter — isolate a single strand for focused testing.
Routes 100% of iterations to the specified strand. Only valid with -fuzz/-fuzz0/-fuzz1/-fuzz2/-fuzz6.
Strand 1 = random ATN generation, Strand 2 = template probe, Strand 3 = random mutation,
Strand 4 = targeted mutation, Strand 5 = template enrichment (multi-Q&A + nested control flow).
Strand 4 also saves mismatch diagnostics to fuzz-crashes/strand4-mismatches/.
- $ ek9 -fuzz6 5 -s4 // 5 minutes, Strand 4 only, HTML dashboard
- $ ek9 -fuzz6 10 -s5 // 10 minutes, Strand 5 only, HTML dashboard
- $ ek9 -fuzz 10 -s1 // 10 minutes, Strand 1 only
Test Generation
EK9 can generate edge-case tests and mutation variants for your code using the compiler's own symbol table. See Test Generation for full documentation including edge-case value pools and mutation categories.
-fuzztest source.ek9 output.ek9 Generate edge-case @Test functions for the given source file. Analyzes the symbol table and generates boundary/edge-case tests, compile-checking each generated test. Output is a compilable .ek9 file with @Test functions for AI or human review. Errors if the output file already exists (use -overwrite to replace).
-fuzzmutate source.ek9 mutations/ Generate mutation variants for test quality assessment. Creates single-point mutations that compile but alter behaviour. Output is a directory of .ek9 variant files with a manifest.txt. Errors if the output directory already exists (use -overwrite to replace).
-test tests.ek9 Run mutation kill-check against a test file. Use with -fuzzmutate to verify that your tests detect the generated mutations. Each mutation variant is compiled and tested — a "killed" mutation means your tests caught the change; a "survived" mutation indicates a gap in test coverage.
-overwrite Allow overwriting an existing output file or directory for -fuzztest and -fuzzmutate. Without this flag, these commands refuse to overwrite existing output to prevent accidental data loss.
-seed <n> Set a reproducibility seed for -fuzztest or -fuzzmutate. Using the same seed produces identical generated tests or mutations, enabling reproducible results across runs.
-n <n> Set the maximum candidate count for -fuzztest (default 200) or -fuzzmutate (default 100). Controls how many test cases or mutation variants are generated.
- $ ek9 -fuzztest mylib.ek9 mylib_tests.ek9 // Generate edge-case @Test functions
- $ ek9 -fuzztest mylib.ek9 mylib_tests.ek9 -overwrite -n 50 // Replace, limit to 50
- $ ek9 -fuzzmutate myapp.ek9 mutations/ // Generate mutation variants
- $ ek9 -fuzzmutate myapp.ek9 mutations/ -overwrite -seed 123 // Replace, reproducible
- $ ek9 -fuzzmutate myapp.ek9 mutations/ -test mytests.ek9 // Generate + kill-check
Optimization Levels
EK9 provides three optimization levels that control the trade-off between compilation speed, debuggability, and runtime performance:
-O0 No optimization. Fastest compile time with maximum debuggability. All coverage probes and debug information are preserved. This level is forced automatically when running tests (-t) to ensure accurate coverage mapping.
-O2 Minimal optimization. A balanced default for normal builds. Applies safe optimizations that don't significantly affect debugging.
-O3 Full optimization. Maximum runtime performance. Applies aggressive optimizations including function inlining and dead code elimination. This is the default when packaging (-P) for deployment. Not compatible with test execution (-t) because optimizations corrupt coverage accuracy.
- $ ek9 -c -O0 myapp.ek9 // Compile with no optimization
- $ ek9 -c -O2 myapp.ek9 // Compile with balanced optimization
- $ ek9 -c -O3 myapp.ek9 // Compile with full optimization
The 'run' options
-d port Run in debug mode (requires debugging information to have been compiled in). The use of edb the EK9 debugger will be covered once developed.
-r Run in normal mode (assumed if no other option provided).
-repl Start the interactive REPL (Read-Eval-Print-Loop). Can be combined with -E0 through -E5 for error verbosity control. See REPL documentation for complete feature reference.
Interactive REPL
EK9 includes a full-featured interactive REPL (Read-Eval-Print-Loop) for exploring the language, prototyping code, and learning EK9 syntax.
Starting the REPL
- $ ek9 -repl ↵
The REPL provides syntax highlighting, intelligent tab completion (including method completion after "."), external editor integration, session management with save/load, buffer editing, and EK9's full error diagnostic system.
REPL with Error Verbosity
Combine with error verbosity flags for enhanced feedback:
- $ ek9 -repl -E2 ↵
This enables "Did you mean?" suggestions for typos and unresolved symbols. See Error Verbosity Levels for examples.
Key Features
- Syntax Highlighting - Keywords, types, strings, numbers, comments color-coded
- Tab Completion - Keywords, types, variables, and methods after "."
- Mode Switching - /function, /class, /record, /trait, /type for definitions
- External Editor - :edit opens $VISUAL or $EDITOR with session source
- Session Management - :save and :load to persist work
- Buffer Editing - :edit N, :del N, :ins N, :undo for line manipulation
- Hover Help - Ctrl+H shows symbol type information
See the REPL documentation for complete details on all features and commands.
Using Standard Input and Output
EK9 programs can read from standard input (stdin) and write to standard output (stdout), making them work seamlessly with Unix-style pipes and shell redirection. This is essential for creating CLI tools, filters, and pipeline-based applications.
Simple Example
Here's a minimal EK9 program that reads from stdin and writes to stdout:
#!ek9
defines module introduction
defines program
PassThrough()
stdin <- Stdin()
stdout <- Stdout()
inputLine <- stdin.next()
stdout.println(inputLine)
//EOF
Running with Pipes
Once compiled, you can use standard Unix piping to pass data to your EK9 program:
- $ echo "Hello World" | ek9 PassThrough.ek9 ↵
- Hello World
On Unix, Linux, and macOS systems with the shebang (#!ek9) and execute permissions set, you can run it directly:
- $ chmod u+x PassThrough.ek9 ↵
- $ echo "Hello World" | ./PassThrough.ek9 ↵
- Hello World
Chaining with Unix Tools
EK9 programs integrate naturally with Unix command-line tools, allowing you to build processing pipelines:
- $ cat data.txt | ek9 filter.ek9 | sort | uniq ↵
Learn More
For comprehensive documentation on Stdin, Stdout, and Stderr usage, including advanced patterns with stream pipelines and iterator-style access, see:
- Stdin documentation - Reading from standard input
- Stdout documentation - Writing to standard output
- Stderr documentation - Error output channel
- Complete CLI application example - 400-line practical example
Exit Codes
The ek9 command uses specific exit codes to enable integration with shell scripts, build systems, and CI/CD pipelines. Understanding these exit codes is essential for automation and error handling in production environments.
How Exit Codes Work
The ek9 command is a wrapper that invokes the EK9 compiler (a Java program). The wrapper translates the compiler's internal exit codes to standard Unix conventions where exit code 0 means success:
- If the compiler returns internal code 0: The compiler has printed a command to run your program. The wrapper executes that command and returns whatever exit code your EK9 program returns.
- If the compiler returns internal code 1: The operation completed successfully with nothing to run (e.g., -C compile only, -V version, -Gk generate keys). The wrapper maps this to exit code 0 (Unix success).
- If the compiler returns internal codes 2-10: The compiler encountered an error. The wrapper returns the same exit code to indicate the specific failure.
Exit Codes You Will See
When you run the ek9 command, you will see these exit codes following standard Unix conventions:
0 - Success. Either a successful operation completed (compilation, versioning, packaging, etc.), or your EK9 program executed and returned 0.
1 - Cannot execute. The system was unable to run the EK9 compiler or your compiled program. Check that EK9 is properly installed and you have the necessary permissions. Error details are printed to stderr.
2 - Invalid parameters. The command line parameters provided were not valid or could not be parsed.
3 - File access error. The specified file was not found or could not be read (permissions). This exit code is only for file system access issues, not for code errors.
4 - Invalid combination of parameters. The parameters provided were individually valid but incompatible when used together.
5 - No programs found. The EK9 file does not contain any programs that can be executed.
6 - Program not specified. The EK9 file contains more than one program, and you must specify which one to run using the -r flag.
7 - Language Server failed to start. The EK9 compiler could not start in Language Server Protocol mode when using the -ls flag.
8 - Compilation failed. The EK9 source code could not be compiled due to syntax errors, parse errors, type errors, or other code issues. This includes files that exist but contain invalid EK9 code. Error messages will be printed to stderr.
9 - Wrong number of program arguments. The program requires a specific number of arguments, but a different number was provided at runtime. This is detected during the generated code's argument validation.
10 - Cannot convert argument to required type. A program argument could not be converted to the type required by the program's parameter (e.g., passing "notInteger" when an Integer is required). This is detected during the generated code's argument conversion.
11 - Test execution failed. One or more @Test programs failed their assertions. This exit code is returned when running tests with -t, -t0, -t1, -t2, or -t3 flags.
12 - Coverage insufficient. All tests passed successfully, but code coverage is below the required threshold (80%). This distinguishes between test failures (exit code 11) and adequate testing quality. The coverage threshold is checked automatically even without the -tC flag.
13 - MCP server failed to start. The EK9 compiler could not start in Model Context Protocol mode when using the -mcp flag.
Exit Codes from Your EK9 Programs
When you use ek9 -r yourProgram.ek9 or ./yourProgram.ek9, if compilation succeeds (compiler returns exit code 0), the wrapper executes your program and returns your program's exit code.
Your EK9 programs can set their own exit codes using the Exception class, which supports holding an exit code. If an Exception propagates back to the main program without being caught, the application will exit with that exception's exit code. See the Exceptions section for details.
This means your EK9 programs can return any exit code (0 for success, non-zero for errors), and that exit code will be propagated through the wrapper to the shell. This is essential for writing CLI applications that work correctly in shell scripts and automation.
Shell Script Usage
In shell scripts and CI/CD pipelines, you can use standard Unix exit code patterns:
- $ ek9 -C myprogram.ek9 ↵
- $ if [ $? -eq 0 ]; then ↵
- $ echo "Compilation successful" ↵
- $ elif [ $? -eq 8 ]; then ↵
- $ echo "Compilation failed" ↵
- $ fi ↵
Or use the simpler standard pattern:
- $ if ek9 -C myprogram.ek9; then ↵
- $ echo "Success" ↵
- $ else ↵
- $ echo "Failed with exit code $?" ↵
- $ fi ↵
CI/CD Integration
Build systems and CI/CD pipelines (such as GitHub Actions, AWS CodePipeline, or Azure Pipelines) will automatically detect non-zero exit codes and mark builds as failed. Exit codes 8, 9, 10, 11, 12, and 13 are particularly important for detecting compilation, runtime, test, coverage, and server startup errors in automated builds.
Summary
There are quite a few options available with the EK9 CLI but in general if you just want to write some source and run it - very few options are actually needed. On Linux/macOS platforms just change the execute bit of your source file (chmod u+x someSource.ek9) and then just run it (./someSource.ek9) as long as you installed the EK9 CLI correctly the code will get compiled and run. On Windows you need to just type ek9 someSource.ek9 for it to get compiled and executed.
Conclusion
Well if you got this far, well done! Because this is the last section.
What's been attempted with EK9 is to bridge the gap between pure software development with a compiled language and the packaging, releasing and publishing of software. But doing it in a way that employs a fairly simple language structure that easy to read/write, but is performant and has a range of sophisticated software engineering design patterns built in.
This is ambitious, difficult (technically) and very hard in terms of building the necessary human ecosystem that is essential to make a programming language successful.
The reason the EK9 language is so large is because it incorporates language structure, new constructs, design patterns, API's, versioning, building, packaging and deployment. But hopefully you will find it can provide value for you as a developer; in layers as you need them.
Only time will tell if we can succeed. But thank you for taking the time to read these documents.
Next Steps
Jump back to the main page and download the compiler and some examples and get started.