EK9 MCP tools
ek9 -mcp starts EK9's MCP server, whose tools compile, query, refactor, test, debug and package an EK9 project - each change checked by the compiler before it is written. Each tool has its own page: what it does, when to use it and when not, its arguments and its real recorded calls. The same catalogue as data: toolingForAi-full.json.
Enquiry
Read-only tools. Always safe; no side effects. Free to call without confirmation prompts.
- Control response size with verbosity: "full" (default — the complete result), "summary" (trim per-item detail — graph/tree tools to depth 1, effective-api to member names), or "none" (collapse every list to a <key>Count total). Scan a wide result at summary or none, then re-issue full scoped to the one anchor you care about — cheaper than paging a huge full response into context.
| Tool | What it does |
|---|---|
| ek9_advise_loop | Answers first: directions[] (each with summary such as 'candidate-stream-aggregation' or 'keep-as-loop', candidateShape, confidence), then the loop{} facts, outputs[], resources[] and unknowns[] - read-only. |
| ek9_ask | Returns the best-matching curated Q&A entries: 'match: strong|weak|id' first, then per entry the id, question, category, Oracle tool, the answer and last the compiled EK9 example (capped by default). |
| ek9_check_module_cycles | Answers first: hasCycles and cycleCount, then cycles[] (each a closed module path with edges[].via naming the source files) and moduleCount - the whole workspace module graph. |
| ek9_check_package_dependency_cycles | Answers with hasCycles, cycleCount and the cycles (closed package paths with their edges) across every package declared in the workspace, plus packagesAnalysed and sccCount. |
| ek9_check_requirements | Answers status (healthy | violations | dangling-anchors) and healthy first, then requirementCount, developedCount, outstandingCount, violations[] (the store is broken), danglingAnchors[] (a @Test names a requirement that does not exist), outstanding[] (the backlog) and unanchoredTests[] (the authoring work-list) - the whole graph, nothing to verify. |
| ek9_explain_error | Returns the curated rich explanation for one EK9 error code - [DIAGNOSIS], [EXAMPLES] (as ek9_ask 'Q<id>' routes), the first example's source inlined as [WORKED EXAMPLE Q<id>], [ACTION], [SEE ALSO] and, when tooling is mapped, [REMEDIATION]. |
| ek9_find_constructs_by_name | Answers first: matchCount, then matches[] (name, fullyQualifiedName, module, genus, file, line, column) - workspace-wide; matches:[] when no top-level construct has that name. |
| ek9_find_inline_candidates | Answers candidates[] (file, line, name, tier worth-inlining | safe, useCount) ranked slop-first, with counts{} - every local '<-' declaration in scope examined. |
| ek9_find_symbols | Answers first: symbolCount, symbolNames, withinNames (Type.method each belongs to), siteCount, byKind, byUse, sites as file.ek9:LINE - then each symbol (kind, within, declaredAt, renameable, counts) with its declared/read/written sites. |
| ek9_find_unused_code | Answers first: deadNames and deadByOwner (owner -> its dead members), complete workspace-wide - then each finding classified. |
| ek9_git_blame | Answers first: lineCount and the range, then one record per line (line, sha, author, email, date, subject, text); verbosity:'summary' collapses them to same-commit runs. |
| ek9_git_branch | Answers first: current, branchCount and branchNames, then per-branch records (name, current, upstream, ahead/behind, gone, sha). |
| ek9_git_diff | Answers first: summary, fileCount, additions/deletions and changedFiles names, then per-file hunks with fromLine/toLine and the unified-diff text (dropped at verbosity:'summary'). |
| ek9_git_log | Answers first: commitCount and commitTotal with a truncation note, then commits (sha, author, date, subject, body, parents; files with includeFileList:true). |
| ek9_git_status | Answers first: summary, branch, ahead/behind, isClean, then stagedFiles / modifiedFiles / untrackedFiles / deletedFiles / conflictFiles names and changedFileCount, then the per-file records with change words. |
| ek9_help | Returns the reference page for one keyword, built-in type or topic - hover summary, the full type API for a built-in type, usage examples - or the keyword index when no keyword is given. |
| ek9_inspect_symbol_at_cursor | Answers first: name, fullyQualifiedName, kind, type, state, declaredAt, then the modifiers, flags, scope, purityContext and the type's operators - one symbol, cursor-precise. |
| ek9_list_files | Answers first: entryCount and paths[] (workspace-relative, the value ek9_read_file takes), then entries[{path, name, kind, size, lastModified}] - never content; direct children unless pathPattern recurses. |
| ek9_list_visible_symbols | Answers first: scopeChain[] innermost to outermost, each scope with its symbols (name, kind, type, state, roles), then activeGuards and purityConstraint. |
| ek9_list_workflows | Returns every named multi-tool workflow - workflowCount, workflowNames, then each workflow's summary and full step sequence. |
| ek9_paradigm | Returns the constant EK9 paradigm summary (syntax that is NOT C/Java/Python, first-attempt traps, concepts with no analogue elsewhere) and working rules - the smallest priming context for an AI about to write EK9 code - and with withExamples:true the compiled inline examples after it. |
| ek9_query_build_status | Answers first: programState, queriesReliable with its reason, buildOutcome, lastPhaseReached, then sourceCount/sourcesClean/sourcesWithErrors and sources[] with per-file error and warning counts. |
| ek9_query_call_graph | Answers first: callerNames / calleeNames and callerSites / calleeSites ('file.ek9:LINE') - then the chain to the requested depth. |
| ek9_query_capability_usage | Answers first: consistent, underDeclared, overDeclared, usedCapabilities, declaredCapabilities and findings, then actualUsage with every call site - the workspace-wide gated-type audit against the package block. |
| ek9_query_classes | Answers first: classNames[], then classes[] (name, module, file, line, extends, traits, isOpen, isAbstract, keyMethods, methodCount) and summary counts - workspace-wide or the filtered subset. |
| ek9_query_complexity | Answers first: in view 'totals' the workspace-wide methodCount, averages, maxima and methodsAboveCyclomaticThreshold / methodsAboveCognitiveThreshold; in 'hotspots' hotspotNames[] then hotspots[]; in 'inputVariety' per-callable floor/ceiling (display-only). |
| ek9_query_components | Answers first: componentNames[], then components[] (name, module, file, line, extends, isOpen, isAbstract, keyMethods, methodCount) and summary counts - the DI-injectable constructs, workspace-wide or the filtered subset. |
| ek9_query_constrained_types | Answers first: constrainedTypeNames[], then constrainedTypes[] (name, module, file, line, constrains, constraint, admissibleWindow, suffix) and summary counts. |
| ek9_query_construct | Answers first: fieldNames, methodNames, operatorNames, defaultedOperatorNames, superName, traitNames, then construct{name, fullyQualifiedName, module, genus, isOpen, extends, traits, modifiers} and the full fields/methods/operators/constructors/metrics. |
| ek9_query_construct_neighbourhood | Answers first: nodeCount, nodes[] (name, fullyQualifiedName, module, genus, file, line, distance), edges[] (from, to, kind) and edgesByKind - the N-hop typed ego graph merging inheritance, calls, composition, references and DI. |
| ek9_query_data_touch | Answers first: anchor and verdicts (parameter → untouched | mutates | escapes | ... |
| ek9_query_deadlock_chain | Answers first: chains[] - per detected lock risk its errorCode, path, outerLock/innerLock and ordered steps[] with file/line/column - chains:[] when nothing is at risk. |
| ek9_query_dependency_injection | Answers first: applicationCount and applications[] (registrations, injectionSites, boundPrograms, health incl. |
| ek9_query_dependency_tree | Answers first: direction, rootPackage, rootVersion, then tree{} (dependsOn) or deduplicated[] with broughtInBy (broughtInBy), selections[] and summary - the transitive package dependency tree across the workspace. |
| ek9_query_diagnostics | Answers first: diagnosticCount, errorCount, warningCount, errorCodes[] and sites[] ('file.ek9:LINE CODE message'), then diagnostics[] in full, byCode and byFile - the Problems View of the last compile. |
| ek9_query_dispatchers | Answers first: routing[] - per dispatcher method its dispatchOn type, typesWithOwnHandler, typesUsingInheritedHandler (served by a supertype's handler) and typesFallingBack (to the dispatchOn entry point's own body), with routingCovers when the lists are whole - then the full dispatcherMethods[] with resolutionTable; on a sealed type, allowedSubtypes[]. |
| ek9_query_effective_api | Answers first: declaredMethodNames, inheritedMethodNames, overrides as 'method:Trait', operatorNames, traitNames - then every member in full with its source and file/line. |
| ek9_query_enter_sites | Answers first: siteCount, then sites[] (stableId, kind, receiver, lockIdentityIds, location, enclosingFunction) - every lock acquisition, workspace-wide. |
| ek9_query_enumerations | Answers first: enumerationNames[], then enumerations[] (name, module, file, line, values in declaration order, valueCount) and summary counts. |
| ek9_query_env_vars | Answers first: names[] (every env-var read), then envVars[] per call site (site, name, accessMethod, sanitization, inConstruct), dynamicAccesses[] and summary counts - type-resolved EnvVars calls, never text matches. |
| ek9_query_flow | Answers first: status, branchCount, loopCount, guardCount, deadBranchCount, then method{name, fullyQualifiedName, signature, declaredAt}, isPure, metrics (cyclomatic/cognitive), flowNodes (the guard-tracked branch/loop tree) and deepAnalysis (provably dead branches, redundant tri-state checks). |
| ek9_query_functions | Answers first: status, functionCount, functionNames - complete for the workspace or the filters given - then functions[] {name, module, file, line, signature, parameters, returnType, isPure, isAbstract}. |
| ek9_query_localisations | Answers first: status, moduleCount, inconsistencyCount, workspaceLocales, then modules[] {name, locales, percentTranslated, methodCount} and inconsistencies[] {locale, supportedIn, missingIn}. |
| ek9_query_lock_analysis | Answers first: status, then deadlockCount, lockIdentityCount, enterSiteCount, keyBodyCount, crossThreadEdgeCount and nextStep (the one drill-down worth calling); lockIdentityCount 0 = no MutexLock anywhere, deadlock structurally impossible. |
| ek9_query_lock_identity | Answers first: status, identityCount, then identities[] {stableId, origin, displayName, originSymbol, originLocation, payload}; stableId joins ek9_query_enter_sites and ek9_query_deadlock_chain. |
| ek9_query_metric_limits | Returns EK9's ENFORCED quality-metric limits (coupling, cohesion, complexity, DI, size) - limitCount and limits[] with ruleCode, metricKey, limitKind, comparator, limit and usableMax - from the single source the checkers fire on. |
| ek9_query_module | Answers first: status, module, constructCount, constructNames, then constructs[] with kind, member counts and quality metrics (complexity, coupling, cohesion). |
| ek9_query_module_cohesion | Answers first: status, programState, moduleCount, then modules[] {name, moduleCohesion (E11017 disconnected groups), cohesionRatio, lcom4 (E11014 over-limit constructs)}; symbol:'Type' drills to one construct's LCOM4. |
| ek9_query_module_coupling | Answers first: status, programState, edgeCount, then edges[] {from, to, types, weight, shape, sites, inCycle, proposals} ranked worst-first, audit (adHocCoupling, overDeclaredReferences candidates) and summary. |
| ek9_query_module_dependencies | Answers first: status, moduleCount, edgeCount, hasCycles, then modules[] {name, files, constructCount}, dependencies[] {from, to, referenceCount, kinds} and metrics (fan-in/out, cycles). |
| ek9_query_module_landscape | Answers first: status, programState, moduleCount, moduleNames, then modules[] {name, band, types, metrics as headroom {rule, limit, value, band, enforced}, cycles} ranked worst-first and summary. |
| ek9_query_mutex_payload | Answers first: status, summary {bodies, contained, mayEscape, unknown}, findingCount, then findings[] {file, line, inConstruct, payloadType, locks, escape, sites[] with via chain and origin}. |
| ek9_query_name_clashes | Answers first: status, name, fullyQualifiedName, clashFree, donorLocals, renames (one globally-safe fresh name per clashing local), callSiteCount, then callSites[] with per-site clashes and the summary line. |
| ek9_query_package | Answers first: status, packageCount, then packages[] {name, version, description, license, tags, publishable, deps, devDeps, excludeDeps, capabilities, sourceLocation} - declared, not resolved. |
| ek9_query_pipeline | Answers first: status, stageCount, then stages[] in order {operator, kind, consumes, produces}, sourceType, resultType and summary.transformations. |
| ek9_query_programs | Answers first: status, programCount, programNames - complete for the workspace or the filters given - then programs[] {name, module, file, line, signature, parameters}. |
| ek9_query_purity_impact | Answers first: status, change, availableChanges, verdict (ready / would-fail / cascade-too-large / blocked-refuse-to-root), callerNames, calleeNames, then anchor, contract, afferent, efferent axes - the same closure ek9_fix_purity_contract applies. |
| ek9_query_records | Answers first: status, recordCount, recordNames - complete for the workspace or the filters given - then records[] {name, module, file, line, fields, extends, traits, isOpen}. |
| ek9_query_references | Answers first: useSiteCount, usedByConstructs, useSites as file.ek9:LINE - then each reference with its source line (omitted above 50 sites unless verbosity:'full'). |
| ek9_query_requirement | Answers status (ok | not-found) and requirementId first, then the node(s): each carries authored{title, body, retired, meta} and derived{developed, anchoringTests, parentChain, children} so a computed rollup is never mistaken for a person's assertion; list and outstanding return requirementCount + requirements[], footprint the anchoringTests and reachedSymbols. |
| ek9_query_sensitive_reveals | Answers first: status, revealCount, violationCount, privilegedCount, violationSites as file.ek9:LINE, then reveals[] {file, line, column, module, inConstruct, inConstructFqn, privilege}. |
| ek9_query_service_routes | Answers first: status, programState, routeCount, byService, then routes[] {verb, uri, fullPath, parameters with binding + sanitized, securityGate, cors, auditWarnings} and summary counts. |
| ek9_query_signature_impact | Answers first: status, direction (the mutation kind), verdict (ready / would-fail), callerSites, then anchor, contract (root + overrides the change cascades to) and afferent (the call sites ek9_change_signature would rewrite, each fixable or breaks). |
| ek9_query_tool_catalogue | Returns the whole EK9 tool inventory grouped by category - toolCount and toolNames per category plus workflowNames by default; verbosity:'summary' adds each tool's description, rules and IDE precedent, 'full' the JSON schemas. |
| ek9_query_tool_detail | Returns one tool's entry - status, match (exact|single|ambiguous|none), then whenToUse, whenNotToUse, description, examples and inputSchema - by name, intent phrase or the error code it remediates. |
| ek9_query_traits | Answers first: status, implementedByAll (when asked), traitCount, traitNames - complete for the workspace or the filters given - then traits[] {name, module, file, line, traitOf, implementedBy, implementedByCount, methods, methodCount}. |
| ek9_query_translation_completeness | Answers status, translationDebtCount and translationDebt[] (every {textType, locale, method} still needing translation) first, then the per-(text type, locale, method) status grid (translated | stubbed | missing-error) and summary totals - the whole module, nothing to verify. |
| ek9_query_type_hierarchy | Answers first: subtypeNames (implementedBy on a trait), superNames, traitNames, allowedSubtypes for a sealed trait - complete workspace-wide - then the full graph. |
| ek9_query_workflow | Returns one named multi-tool workflow's ordered steps (tool + one-line reason each), or with no name every workflow with workflowNames first. |
| ek9_query_workspace | Answers first: status, moduleCount, moduleNames, constructCount, then modules[] {name, constructCount, constructs[] {name, category, genus}}; verbosity:'none' lists modules only, 'full' adds per-construct detail. |
| ek9_read_construct | Answers first: source.text with source.file/startLine/endLine from the compiled symbol-table boundaries (no line guessing), construct {name, fullyQualifiedName, kind}, members[{name, kind, signature, startLine, endLine}] and source.contentHash. |
| ek9_read_file | Answers first: content (numbered 'N| ' when lineNumbers:true), contentHash for expectedContentHash, and for .ek9 the structure outline {module, constructs[{kind,name,startLine,endLine,signature}]} - whole file up to 2,000 lines, truncated:true first when cut. |
| ek9_render_specification | Answers status (ok | not-found), requirementId and markdown - the specification document generated from the requirement graph with every section marked authored or derived - plus anchorsResolved saying whether a compile backed the derived sections. |
| ek9_search_text | Answers first: matchCount, files[], sites['file.ek9:LINE'] (truncated:true first when cut), then matches[{file,line,column,snippet}] - a literal or regex grep across the workspace with EK9-aware exclusions (build outputs, .ek9-cache/, dot-directories). |
| ek9_verify_method | Answers first: status, name, verified, then counterexampleCount, counterexamples[] {obligation, witness, suggestedTest, suggestedFix}, provedSafe, deadBranches and nextStep. |
| ek9_version | Returns the EK9 compiler toolchain version string, e.g. |
Editor
Mutate source or package directive. Produce a reviewable changeset; default policy is confirm-on-write.
- After a sequence of editor calls, run
ek9_compile(orek9_run_tests) to verify. - Call with dryRun:true first to preview the changeset — status is ready / would-fail / conflicts — then re-issue the SAME args with dryRun:false to apply.
- Control response size with verbosity: "full" (default — every edit's before/after bodies), "summary" (keep each edit's file/type/line range, drop the bodies), or "none" (just editCount + the risk block). On an apply after a dry-run already showed the render, verbosity:"summary" — or its retained alias terse:true — keeps what changed where without paying for the content twice.
- Pass terseErrors:true to collapse would-be diagnostics to one line each (code/file/line/message); recover the full explanation for any code with
ek9_explain_error<code>.
| Tool | What it does |
|---|---|
| ek9_add_application | Appends the application to the file's 'defines application' block (created if absent), one 'register Component() as Interface' line per registration; answers status, edits[] and summary, with a would-fail carrying the compiler's own diagnostics. |
| ek9_add_capability | Answers with the edit that declares one gated-type capability in the 'capabilities <- [...]' List of a 'defines package' block, plus the resolved capability name. |
| ek9_add_constructor | Inserts one constructor at the construct's canonical member position; answers status, edits[] and summary, a same-shape constructor as conflicts[] (constructor-already-exists, with its line). |
| ek9_add_dependency | Answers with the edit that appends one runtime or dev dependency to the deps/devDeps Dict of a 'defines package' block - source only, nothing is fetched. |
| ek9_add_field | Inserts the field declaration at the construct's canonical field position; answers status, edits[] and summary, a clashing name as conflicts[] (name-collision). |
| ek9_add_method | Inserts the method (signature, a require-guarded stub body and the return) at the construct's canonical member position; answers status, edits[] and summary, a same-signature method as conflicts[] (signature-collision). |
| ek9_add_operator | Inserts the operator declaration (or the bare 'default operator' block) at the construct's canonical operator position; answers status, edits[] and summary - 'unchanged', naming where it is, for a default operator the construct already declares; statements[] for an operator already written by hand replace its body, and body:'explicit' over one names the insert route in conflicts[]. |
| ek9_add_program | Appends the program (or @Test program) to the file's 'defines program' block, created if absent, with a stub body that references every parameter and injection; answers status, edits[] and summary. |
| ek9_add_route | Inserts the web operation (`byId() as GET for :/{id}` or `operator += for :/`) with a compiling stub body into the service; answers status, edits[] and summary, a duplicate route as conflicts[] (route-collision). |
| ek9_add_to_sealed_allowlist | Rewrites the sealed type's 'allow only' line with the new subtypes appended; answers status, edits[] and summary, each bad entry as conflicts[] (target-not-sealed, entry-does-not-extend-target, entry-already-in-allowlist). |
| ek9_adopt_trait | Appends 'with trait of <Trait>' (or '… by <field>') to the construct's declaration and, when implementing, one override stub per abstract trait method; answers status, edits[] and summary, an already-adopted trait as conflicts[] (trait-already-adopted). |
| ek9_anchor_test | Rewrites the @Test directive line above the program to '@Test: "REQ:x"' (the execution group kept); answers status, edits[] and summary, an unchanged directive as conflicts[] (already-anchored). |
| ek9_apply_guard_pattern | Rewrites the construct's head to 'if x <- f()' (or ':=?', or ':=' with an explicit 'then x?', as the source assignment dictates) and deletes the standalone assignment and the redundant 'x?' check; answers status, edits[] and summary, an unsafe or unsupported shape as conflicts[]. |
| ek9_apply_symbolic_fix | Inserts the 'require <divisor> <> 0' line guard-first (an inline-initialised return becomes '<- rtn as T?' + ':=?'), re-finding the counterexample server-side, and migrates a pinning @Test to assertPanic in the same changeset; answers status, edits[] and summary. |
| ek9_change_signature | Rewrites the declaration and EVERY call site atomically (add / remove / reorder parameters, change the return type, toggle 'as pure'); answers status, edits[] and summary with the call-site count, a blocking call site as conflicts[] (callsite-incompatible-with-new-signature). |
| ek9_change_visibility | Rewrites the method's declaration line with the new access modifier (public = none); answers status, edits[] and summary, an unchanged method as conflicts[] (already-<visibility>). |
| ek9_collapse_to_default_operator | Replaces the operator's declaration and body with the one-line 'default operator <sym>' form (the inverse of ek9_expand_default_operator); answers status, edits[] and summary. |
| ek9_convert_constructor | Replaces the no-arg constructor with its other spelling - 'default Name()' ↔ an explicit 'this.field :=? Type()' default-setter body - purity and visibility preserved; answers status, edits[] and summary. |
| ek9_create_dynamic_class | Inserts `variableName <- (captures) trait of T as class` (or the tuple / generic form) with its members after the line, auto-adding `default operator ?` for captures; answers status, edits[] and summary, with a would-fail carrying the compiler's own diagnostics (unimplemented abstract methods named). |
| ek9_create_dynamic_function | Inserts `variableName <- (captures) is|extends Base as [pure] function` with its body (or an inline `(expr)`, or an //AI: stub) after the line; answers status, edits[] and summary, with a would-fail carrying the compiler's own diagnostics. |
| ek9_create_requirement | Writes the requirement nodes as flat markdown files under .ek9-ai/requirements/ (one atomic batch, each keyed by its frozen slug) and answers the editor envelope: status (applied | ready | conflicts), written, edits[] and summary naming the ids created. |
| ek9_delete_directory | Answers first: status (applied | ready | conflicts), written and edits[{file, type:delete, kind:directory}] - removes an EMPTY workspace directory, never a populated tree. |
| ek9_delete_file | Answers first: status (applied | ready | conflicts | would-fail), written and, on a refusal, referenceCount + referencingFiles[] before the per-site conflicts[]; edits[{file, type:delete, disposition}]. |
| ek9_edit_file | Answers first: status (applied | ready | would-fail | conflicts), written, edits[{file, startLine, endLine, before, after}], wouldBeDiagnostics from the verifying compile and contentHash on an applied edit - an atomic batch of text edits to one file, or to several as one apply. |
| ek9_edit_localized_text | Rewrites the `defines text for "<locale>"` blocks of one text type in every locale that defines it (one atomic edit, so E07150 locale-completeness holds) and answers the editor envelope: status (applied | ready | would-fail | conflicts | error), written, edits[], summary, and translationDebt[] naming each {textType, locale, method} left placeholder-stubbed. |
| ek9_exclude_transitive_dependency | Answers with the edit that adds an excludeDeps entry (module -> viaModule) to a 'defines package' block, blocking a transitive dependency a parent pulls in. |
| ek9_expand_default_operator | Replaces the 'default operator' declaration with the explicit body the compiler would synthesise from the fields, ready to customise; answers status, edits[] and summary, a missing default line as conflicts[] (target-not-a-default-operator). |
| ek9_extract_constant | Appends `name <- literal` to the module's `defines constant` block (created if absent) and replaces every occurrence of the literal in the file with the name; answers status, edits[] and summary with the occurrence count, a clashing name as conflicts[] (constant-name-collision). |
| ek9_extract_method | Inserts the new method (parameters and return inferred from variable data-flow) and replaces the block with a call to it; answers status, edits[] and summary, an ambiguous or boundary-crossing block as conflicts[]. |
| ek9_extract_to_localized_text | Replaces the selected string literal with `<localeAccessor>.<name>(args)` and adds the text method to every locale of the i18n file in one atomic changeset, answering the editor envelope: status (applied | ready | would-fail | conflicts | error), written, edits[], summary and translationDebt[] naming the locales left placeholder-stubbed. |
| ek9_extract_trait | Appends a new 'defines trait' block declaring the chosen methods as abstract, adds 'with trait of <Name>' to the class header and 'override' to each method; answers status, edits[] and summary, a non-extractable member as conflicts[] (member-not-extractable-to-trait). |
| ek9_extract_variable | Inserts `name <- expression` before the first occurrence and replaces every matching occurrence in the enclosing block with the name; answers status, edits[] and summary, a side-effecting multi-occurrence expression as conflicts[]. |
| ek9_fix_purity_contract | Adds or removes 'as pure' on the callable the diagnostic names, with the override cascade applied; answers status, edits[] and summary, the horizontal cascade as advisories[] and a mode/diagnosis mismatch as conflicts[]. |
| ek9_format | Rewrites the file in canonical EK9 style (indentation, spacing, blank-line and line-break conventions); answers status, edits[] (one per changed line) and summary, an unparseable file as conflicts[] (source-not-parseable). |
| ek9_generate_delegation | Rewrites the class header's 'with trait of <Trait>' clause to '... |
| ek9_generate_dispatcher | Inserts the '<name>() as dispatcher' entry with its fallback body plus one same-named handler overload per subtype of the base type; answers status, edits[] and summary naming any existing handlers kept. |
| ek9_implement_methods | Inserts an 'override' stub for every abstract trait method the class has not implemented; answers status and edits[] (one INSERT block), or an error carrying the resolutions[] a concrete-diamond collision needs. |
| ek9_inline_function | Replaces every call to a FUNCTION or METHOD with its parameter-substituted body and deletes the declaration; answers status, edits[] (one REPLACE per call site + the DELETE) and conflicts[] (kind 'variable-clash' with {name, suggestedName}). |
| ek9_inline_variable | Deletes a single-assignment local's declaration and substitutes its initialiser at every use site (including `${...}` holes); answers status, edits[] and conflicts[] (variable-reassigned, impure-initialiser-multi-use, ...). |
| ek9_insert_coalescing | Splices `LEFT <op> RIGHT` in place of a selected single-line left operand using one of the EK9 coalescing / elvis operators; answers status, edits[] (one REPLACE) and conflicts[] (kind 'selection-not-an-expression'), with a type-incompatible pairing surfacing as would-fail. |
| ek9_insert_statements | Splices EK9 statement(s) into a named method/function/operator body at anchor top, bottom, replace or a body line, re-indented by the tool; answers status, edits[] (one INSERT), insertedLineRange and resultingBodySnippet, or error.problems[] naming the entry that does not parse. |
| ek9_introduce_field | Lifts a local and its initialiser to a same-named field of the enclosing class/record/component and deletes the local (adding `default operator ?` when it is the first field); answers status, edits[] and conflicts[] (no-promotable-declaration, not-inside-fielded-aggregate, field-name-collision). |
| ek9_introduce_parameter | Appends a new parameter to the enclosing method/function, replaces the selected in-body expression with it and passes the ORIGINAL expression at every call site (Fowler "Introduce Parameter"); answers status, edits[] and conflicts[] (value-expression-not-a-single-expression, type-not-inferable, ...). |
| ek9_make_abstract | Rewrites the declaration to 'as abstract' (replacing any 'as open') so the construct can no longer be instantiated; answers status, edits[] and wouldBeDiagnostics with every direct construction site (E10030). |
| ek9_make_closed | Strips 'as open' from the declaration so the construct can no longer be extended; answers status, edits[] and conflicts[] naming every subtype (kind 'subtype') that would break with E05030. |
| ek9_make_concrete | Removes 'as abstract' from the declaration (keeping 'as open' unless keepOpen:false) so the construct can be instantiated; answers status, edits[] and conflicts[] listing every remaining abstract member (kind 'abstract-method'). |
| ek9_make_open | Appends 'as open' to the declaration so the construct can be extended; answers status and edits[] (one REPLACE on the declaration line), or conflicts[] when it is already open. |
| ek9_move_construct | Relocates one top-level construct to another .ek9 file, rewriting every workspace 'references' entry when the move changes module; answers status, edits[] (source DELETE, target INSERT, one rewrite per referring file) and conflicts[]. |
| ek9_move_file | Answers first: status (applied | ready | conflicts), written and edits[{file, newFile, type:move}] - a pure file-system relocation of any workspace file, contents untouched. |
| ek9_new_construct | Scaffolds one top-level construct (class/record/trait/component/function/type/constant/service) into an EXISTING module file, or a new package.ek9 for mode:'package'; answers status, edits[] (one INSERT, or one CREATE for a package), stubs[] to fill with ek9_insert_statements, added[] and nextStep. |
| ek9_organize_constants | Moves every `defines constant` declaration of one module into one block in one file (created when targetFile is new); answers status, edits[] (one INSERT + one DELETE per moved declaration) and conflicts[] (comments-in-block, module-ambiguous, target-file-ambiguous, pre-existing-duplicate-constant). |
| ek9_organize_localized_text | Moves the `defines text for "<locale>"` blocks between files to the chosen layout - block content preserved verbatim, donors kept as residual stubs, never deleted - and answers the editor envelope: status (applied | ready | conflicts | error), written, edits[] and summary; an already-canonical layout is applied with empty edits[]. |
| ek9_organize_references | Deletes the unused entries of one file's 'references' block (usage judged by a scratch compile, so functions, types and name-collisions are all right) and answers the editor envelope: status (applied | ready | error), written, edits[] - one delete per unused line - and summary; an already-clean file is applied with empty edits[]. |
| ek9_promote_to_constant | Moves a `name <- literal` declaration into the module's `defines constant` block (same name, original deleted); answers status, edits[] and conflicts[] (no-promotable-declaration, initialiser-not-a-literal, constant-name-collision). |
| ek9_prune_empty_sources | Deletes every .ek9 file that is a bare zero-construct module stub (shebang + 'defines module' + //EOF, line comments allowed); answers status, edits[] (one DELETE per file) and skipped[] with a reason per retained candidate. |
| ek9_pull_up | Moves the named methods/operators from a subclass into its superclass, dropping 'override' on the moved declarations; answers status and edits[] (one DELETE per member + one INSERT on the superclass). |
| ek9_push_down | Removes the named methods/operators from a superclass and copies them into each named direct subclass; answers status, edits[] (one DELETE + one INSERT per subclass) and conflicts[] (subclass-not-direct, target-is-only-source-class). |
| ek9_remove_capability | Answers with the edit that revokes one gated-type capability from the 'capabilities <- [...]' List of a 'defines package' block, plus the resolved capability name. |
| ek9_remove_comments | Deletes one whole-line comment block (//, <!- -!>, <!-- --> or <?- -?>) in full; answers status and edits[] (one DELETE per line), or conflicts[] (kind 'comment-shares-line-with-code') when a boundary line also carries code. |
| ek9_remove_dependency | Answers with the edit that deletes one entry from the deps or devDeps Dict of a 'defines package' block (the whole Dict when it was the last entry). |
| ek9_remove_field | Deletes a field from a class/record/component; answers status and edits[] (one DELETE), or conflicts[] with every in-body reference classified by 'kind' and a suggestedRepair for the mechanical ones. |
| ek9_remove_statements | Deletes a contiguous statement range from one method/function/operator body; answers status and edits[] (one DELETE per line), or conflicts[] (range-straddles-method-boundary, range-not-on-statement-boundary, removed-statement-declares-used-local, removal-is-a-replacement, range-empties-body). |
| ek9_remove_transitive_exclusion | Answers with the edit that deletes one excludeDeps entry from a 'defines package' block, re-allowing a previously-blocked transitive dependency. |
| ek9_rename_field | Renames a private field and every use inside its owning construct body in one atomic edit; answers status and edits[] (one REPLACE per rewritten line). |
| ek9_rename_file | Answers first: status (applied | ready | conflicts), written and edits[{file, newFile, type:move}] - a pure file-system rename of a .ek9 source, contents and module identity untouched. |
| ek9_rename_symbol | Renames a symbol and every workspace reference to it atomically across all files (references blocks and `${...}` holes included); answers status, edits[] per site and conflicts[] (name-collision-in-target-scope, convention-mismatch, symbol-not-renameable). |
| ek9_rewrite_string_concat | Replaces a selected `"a" + var + "b"` concat with the equivalent backtick interpolation, escaping backtick and `$` in literal segments; answers status and edits[] (one REPLACE), conflicts[] (selection-not-a-string-expression, operand-has-no-string-operator with a suggestedRepair), or status:unchanged when the selection is already a backtick literal. |
| ek9_safe_delete | Deletes a top-level construct or a class/record/component member - or several as one change - after a workspace-wide reference check; answers status and edits[] (one DELETE per line), or conflicts[] with one 'construct-still-referenced' entry per citing site. |
| ek9_seal_type | Adds 'allow only A, B, C' to a class or trait declaration (plus 'as open' on a class that has no extensibility modifier); answers status, edits[] and conflicts[] naming any entry that does not extend the target or any existing subtype left off the list. |
| ek9_surround_with | Folds a contiguous line range under an if / if-else / try-catch / try-catch-finally / for-range / while head, re-indenting the block per EK9's brace-free rules; answers status and edits[] (one REPLACE carrying the head + the re-indented lines, one DELETE per absorbed line). |
| ek9_sync_references | Rewrites one file's 'references' block - adding the module::Name entry for each cross-module symbol the file uses but has not declared (E50001/E50010) and deleting each entry nothing uses - and answers the editor envelope: status (applied | ready | conflicts | error), written, edits[] and summary ('Added N and removed M reference(s)'). |
| ek9_toggle_block_comment | Wraps a whole-line range in EK9 block-comment markers (<!- ... |
| ek9_unseal_type | Removes the 'allow only A, B, C' clause from a sealed class or trait, keeping its 'as open' / 'as abstract'; answers status and edits[] (one REPLACE on the declaration line), or conflicts[] (kind 'already-unsealed') when there is no clause. |
| ek9_update_requirement | Rewrites one existing requirement node's markdown file (body, title, meta, position, retirement) or deletes it, and answers the editor envelope: status (applied | ready | conflicts), written, edits[] and summary naming the mode applied. |
| ek9_write_file | Answers first: status (applied | ready | would-fail | conflicts), written, edits[{file, type:create|overwrite, bytesWritten}] and contentHash; a .ek9 write carries wouldBeDiagnostics from the verifying compile, any other file is written as-is. |
Execution
Run code or tooling. Most expensive, most side-effecting; default policy is confirm-on-execute.
| Tool | What it does |
|---|---|
| ek9_clean | Wipes the on-disk .ek9/ artefacts the scope names and resets the server JVM's in-memory coverage/profiling runtimes; answers status:ok with cleanedSources[] listing what was wiped or reset, in order. |
| ek9_compile | Compiles the workspace and answers status (ok | failed | found-no-sources | blocked), sourceCount, errorCount, warningCount and diagnostics[] - each with file, line, column, severity, errorCode and message, the ek9_query_diagnostics record - for every discovered .ek9 file. |
| ek9_debug_control | Continues, pauses, steps or sets breakpoints in the current debug session; answers its new runState, sequence and stops. |
| ek9_debug_inspect | Reads what runs recorded - a failure's account, where a value first went wrong, failing and passing runs compared, a report to share - and the current debug session by field (the recorded stop, a frame's locals, path values, the threads), never running the debuggee. |
| ek9_debug_observe | Runs the current debug session until a condition holds or the budget bites, reading the watched paths at every hit of the given lines; answers stoppedBecause, exact hits and the rows. |
| ek9_debug_session | Runs a program under the debugger - several inputs at once with a change journal (sweep), one run to its end, or step by step - and reports, waits on or ends THE debug session (one per server); answers status, runState, sequence, the stops, breakpoints and nextStep. |
| ek9_generate_edge_case_tests | Writes a compile-checked edge-case @Test program file for one .ek9 source and answers status (applied | ready | unchanged | blocked | error), written, testCount, the echoed seed and modifiedFiles[] - every harvested constructor, method, operator and function gets the tri-state UNSET value among its inputs. |
| ek9_git_add | Reports stagedPaths and stagedPathCount (what this call staged), then indexAfter and indexAfterCount (everything now staged) and a summary line. |
| ek9_git_commit | Reports newSha and previousSha, branch, subject, changedFiles and changedFileCount; local history only, nothing is published until ek9_git_push. |
| ek9_git_fetch | Reports updated, upstream, behind and ahead, a summary line and a nextStep when behind; git's own report under gitReport. |
| ek9_git_init | Reports branch and gitignoreCreated (a .gitignore for the generated .ek9/ directory is scaffolded when absent); refuses when already a repository. |
| ek9_git_merge | Reports status and outcome (already-up-to-date, fast-forward, clean-merge or conflict), newSha/previousSha, commitsMerged, changedFiles and conflictFiles; a conflicting merge aborts with the tree restored. |
| ek9_git_pull | Reports commitsPulled, newSha and previousSha, changedFiles and changedFileCount; a dirty tree is refused and a rebase/merge conflict is aborted with the tree restored. |
| ek9_git_push | Reports remote, branch, upstream, upToDate and a summary line, with git's own report under gitReport; outward-facing and not trivially reversible, so confirm intent first. |
| ek9_git_restore | Reports mode, paths and pathCount and a summary line; ref restores content from that commit instead of the index or HEAD. |
| ek9_git_revert | Reports newSha, revertedSha, previousSha, branch, subject, changedFiles and changedFileCount; a conflicting revert aborts with the tree restored. |
| ek9_git_stash | Reports status (stashed, popped, applied, dropped or nothing-to-stash) and the stash ref; mode:'list' returns stashCount and stashes; a conflicting pop keeps the entry (stashPreserved:true). |
| ek9_git_switch | Reports status (switched or created), branch and previousBranch; a dirty tree that would be overwritten is refused with the route (commit, stash or restore first), never auto-stashed. |
| ek9_run_quality_checks | Compiles, runs the tests and answers status (ok | compile-failed | no-tests-found | tests-failed | coverage-low) with tests:{passed, failed}, coverage (overall, methods, lines, branches, byModule), complexity.hotspots[], readability, injections, uncoveredMethods[] and the advisory lockPayloads - every quality metric in one call, extracted in-process. |
| ek9_run_tests | Compiles and runs the project's @Test programs (auto-forcing -Cd -O0 so coverage probes map to source) and answers status (ok | compile-failed | no-tests-found | tests-failed | coverage-low), tests:{passed, failed}, overallCoverage, results[] per test, plus the inputVariety and hex change-risk blocks. |
Arguments every tool takes
Most tools also take these; each tool's page lists only its own.
| Argument | Type | Required | What it is |
|---|---|---|---|
dirtyOverlay | array of object | Universal — see §1.1. Override on-disk content for files with unsaved buffers. Entries are applied at read time; the apply path still writes the (post-edit) result to disk. | |
dryRun | boolean | Universal — see EK9_TOOL_SPECIFICATIONS.md §1.1. When true, no disk mutation; response shows the would-be edit. | |
expectedWorkspaceHash | string | Universal — see §1.1. Drift-detection hash from a prior dry-run. Mismatch emits a WORKSPACE_DRIFTED warning. | |
showExamples | boolean | Universal — the inverse of terseErrors. When true each wouldBeDiagnostics entry is enriched with a 'richExplanation' field inlining that error code's rich explanation (diagnosis + correct-pattern action + 'ek9 -q N' worked-example pointers — the same text ek9_explain_error returns), so a would-fail dry-run carries the corrective pattern without a second call. terseErrors takes precedence if both set. | |
terse | boolean | Universal — token-saver. When true the response omits each edit's before/after bodies (keeping skeletal file/type/line range). Use on an apply after a dryRun already showed the full render — you keep WHAT changed WHERE without re-sending the content. | |
terseErrors | boolean | Universal — token-saver. When true each wouldBeDiagnostics entry collapses to its one-line message + errorCode/file/line (the multi-paragraph explanation is dropped). Recover full detail on demand with ek9_explain_error <errorCode>. | |
verbosity | string: full | summary | none | Universal response-size control (smaller / less detail / summary) — see §1.6. full (default) reproduces the complete response; summary drops each edit's before/after bodies (keeping file/type/line range); none collapses the edits array to a count. The `terse` boolean is the retained alias for summary. |
Workflows
Tools used together, in order, for a common job.
release
Bump version + run tests with coverage + build artefact + install locally + verify.
ek9_increment_version- Bump the appropriate version part (typically patch after a fix).ek9_run_tests- Verify nothing regressed; produces the coverage report as a side effect.ek9_run_quality_checks- Run full quality checks — coverage, complexity, readability, DI — to confirm nothing has degraded since the last release.ek9_package- Build the deployable artefact at the new version.ek9_install_package- Install into ~/.ek9/lib so sibling workspaces can pick it up.ek9_query_package_version- Verify the installed version matches what was bumped.
feature_branch_start
Set feature-branch version + add new dependencies + resolve + verify.
ek9_set_feature_version- Mark the package as on a feature branch (e.g. 2.1.0-PAYINTEG-0).ek9_add_dependency- Declare each new package dependency the feature requires.ek9_resolve_dependencies- Pull the new dependencies into ~/.ek9/lib.ek9_compile- Verify the package still compiles with the new deps.ek9_run_tests- Verify existing tests still pass before any feature work begins.
investigate_build_failure
Diagnose dependency-resolution or compilation failure: diagnostics → tree → cycles → fix → re-resolve.
ek9_query_diagnostics- Read the specific compiler/resolver error messages.ek9_query_dependency_tree- See the resolved tree with version selections and any rejection reasons.ek9_check_package_dependency_cycles- Rule out a transitive cycle in the published-package graph.ek9_resolve_dependencies- Re-resolve after any fix to the package directive.ek9_compile- Confirm the build now succeeds.
investigate_runtime_defect
A runtime failure whose cause is earlier: journal the value over failing AND passing runs -> compare -> leadingTo -> firstWhere -> confirm with one input changed -> report with a finding.
ek9_debug_session- {action:'launch', run:'toEnd', args:<the failing input>}: reproduce the failure once - its message usually names the value that went wrong (a Panic on 'require total >= NOTHING' in Order.invoice -> watch Order.total).ek9_debug_session- {action:'sweep', inputs:[...], journal:{property:'Type.property', hypothesis}}: one run per input set, all with ONE seed. Include inputs you expect to PASS as well as the failing one - compare needs both; every change to the value, on every object, is recorded. Its answer already carries compare's top differences, and the investigation id.ek9_debug_inspect- {action:'compare', runs, hypothesis}: what only the failing runs did - a step they took, a step they LEFT OUT (onlyInPassing), or none (then the values differ). A tie or thin evidence means more inputs, not a verdict. Cite each difference by its run and ticks.ek9_debug_inspect- {action:'leadingTo', runId:<a failing run>, hypothesis}: the account - the changes that led to its failure, each with the line, the values and the calls that made it. Cite ticks for every claim.ek9_debug_inspect- {action:'firstWhere', runId, condition:'total < 0', hypothesis}: the step where the value first went wrong - usually the line to fix.ek9_debug_session- {action:'launch', run:'toEnd', seed:<the sweep's>, args:<one input changed>, journal}: confirm the suspect - the same run with only the suspect's input changed should pass. Without this, a difference is a suspect, not a cause.ek9_debug_inspect- {action:'report', runs, hypothesis, finding:'cause and fix, citing t5 and Orders.ek9:36'}: write the investigation up for the person (index.html, report.json); the finding is shown as yours.