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.
When to use it
You are creating a file or replacing one whole - one call with path + content; a .ek9 path is compile-verified, any other file is written as-is. On create a .ek9 path gets the shebang / defines module / //EOF boilerplate when missing; a verified apply is rolled back on new errors.
When not to use it
- A few text-level changes inside an EXISTING file - use
ek9_edit_file(find/replace, line-replace, regex) rather than rewriting the whole file. - Reading existing file content — use
ek9_read_file(the read counterpart). - Reformatting or semantically mutating existing .ek9 source — use
ek9_format, or the semantic editors (ek9_add_field,ek9_add_method,ek9_move_construct); don't read-modify-write through this tool. - Renaming or deleting a file — use
ek9_move_file/ek9_delete_file(metadata ops, not content writes).
Details
fileKind is inferred from the extension (.ek9 → ek9-source); pass it only to override. Boilerplate handling is create-only and idempotent on all three markers; on overwrite of ek9-source, missing markers attach warnings rather than mutating edited content. A .ek9 dry run scratch-compiles the would-be file (ready / would-fail); a .ek9 apply is verified by the post-write compile and rolled back on new diagnostics (would-fail + apply-rolled-back advisory, written:false) - wouldBeDiagnostics is present only on a verified write. Non-.ek9 targets are written without compile checking (non-ek9-file-not-compile-checked advisory). Writes are workspace-bounded and UTF-8; expectedContentHash (the contentHash ek9_read_file returned) guards overwrites against lost-update races; every applied write returns the new contentHash. An explicit module that diverges from the path-derived one attaches a module-name-mismatches-path warning — the write still succeeds.
Arguments
| Argument | Type | Required | What it is |
|---|---|---|---|
content | string | yes | Content to write. For a .ek9 path on create, may be body-only — the writer prepends shebang + defines module and appends //EOF when missing. |
createIntermediateDirs | boolean | When true (default), missing parent directories are created automatically. | |
expectedContentHash | string | The contentHash ek9_read_file (or a prior write) returned for the file's CURRENT content; the write is refused when the file changed since (lost-update protection). | |
fileKind | string: text | ek9-source | env | config | Inferred from the extension (.ek9 → ek9-source, else text); pass it only to override. ek9-source: boilerplate injection on create + compile verification; env: KEY=VALUE; config: reserved. | |
mode | string: auto | create-only | overwrite-only | auto (default): create or overwrite; create-only: conflict if the file exists; overwrite-only: error if it doesn't. | |
module | string | Fully-qualified EK9 module name for a .ek9 create. Optional — defaults to the path-derived module under the workspace source root; an explicit value that differs emits a 'module-name-mismatches-path' warning. | |
path | string | yes | File path: workspace-relative (preferred) or absolute inside the workspace. Created when absent (mode auto). |
It also takes the arguments every tool takes.
Recorded calls
Real calls, recorded against small projects and checked on every build - a changed answer fails it. 3 of the 11 recorded are shown.
Write negated membership as sent
Request
{
"content" : "#!ek9\ndefines module com.example.names\n\n defines function\n\n isNew() as pure\n ->\n name as String\n names as List of String\n <- rtn as Boolean: not name in names\n\n//EOF\n",
"mode" : "create-only",
"path" : "Names.ek9"
}
Response
{
"conflicts" : [ ],
"contentHash" : "sha256:109c174f2975113c5d175a4ad480666eecec1141e785453f2eda39fdc0dcbd7f",
"edits" : [ {
"boilerplateInjection" : {
"eof" : "preserved",
"module" : "preserved",
"shebang" : "preserved"
},
"bytesWritten" : 194,
"file" : "Names.ek9",
"type" : "create"
} ],
"meta" : {
"serverMs" : "<timing>"
},
"risk" : {
"crossesModuleBoundary" : false,
"estimatedSeverity" : "trivial",
"fileCount" : 1,
"lineCount" : 0,
"touchesPublicApi" : false,
"touchesTests" : false
},
...
Cut short here: 6 more lines. The whole recorded call.
Write new ek9 file verified apply
Request
{
"content" : "#!ek9\ndefines module com.example.greeter\n\n defines function\n greet()\n stdout <- Stdout()\n stdout.println(\"hello\")\n\n//EOF\n",
"path" : "greeter.ek9"
}
Response
{
"conflicts" : [ ],
"contentHash" : "sha256:b39ae77c04a1126bb3aff9a756cf2e40155c298a86cc5381db1b449bb71b8ee0",
"edits" : [ {
"boilerplateInjection" : {
"eof" : "preserved",
"module" : "preserved",
"shebang" : "preserved"
},
"bytesWritten" : 135,
"file" : "greeter.ek9",
"type" : "create"
} ],
"meta" : {
"serverMs" : "<timing>"
},
"risk" : {
"crossesModuleBoundary" : false,
"estimatedSeverity" : "trivial",
"fileCount" : 1,
"lineCount" : 0,
"touchesPublicApi" : false,
"touchesTests" : false
},
...
Cut short here: 6 more lines. The whole recorded call.
Write new text file apply
Request
{
"content" : "Hello from probe.\n",
"mode" : "create-only",
"path" : "NOTES.txt"
}
Response
{
"advisories" : [ {
"kind" : "non-ek9-file-not-compile-checked",
"message" : "Target is not an .ek9 source — written without compile verification."
} ],
"conflicts" : [ ],
"contentHash" : "sha256:11c8e9f77d5df33f6a3b6e75f853c3bb151353b39bc07ec6c849186d5aaabc3b",
"edits" : [ {
"bytesWritten" : 18,
"file" : "NOTES.txt",
"type" : "create"
} ],
"meta" : {
"serverMs" : "<timing>"
},
"risk" : {
"crossesModuleBoundary" : false,
"estimatedSeverity" : "trivial",
"fileCount" : 1,
"lineCount" : 0,
"touchesPublicApi" : false,
"touchesTests" : false
},
"status" : "applied",
...
Cut short here: 4 more lines. The whole recorded call.
See also
- Show me in the IDE: New EK9 File, New Directory, Delete File, Delete Directory