writeAppFile
Create or replace one source file of a Sasha App you manage
Create a file (omit expectedVersion; refused if it exists) or replace one in full (pass the version from readAppFile; refused if the file changed). The change is LIVE immediately. There is no draft and no undo. Allowed: text files with extensions .md .html .css .js .sql .yaml .yml .json .txt .svg, up to 1 MiB, inside the package. A migration that is already applied on this instance must not be edited. Add a new migrations/NNN-*.sql instead. If this call returns an error, the change may still have landed. Call readAppFile before retrying. The result carries status: when status.ok is false the app is NOT usable until the listed diagnostics are fixed. Each names the package file, the line when known, the error code and a reason token. Fix the file and check again; the app is live as soon as it validates.
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
app | string | required | The app id (lowercase kebab-case), as shown by open_app__<id> or listAppFiles. |
path | string | required | Package-relative path such as APP.md, index.html, styles.css, app.js, schema.sql, migrations/002-add-code.sql or actions/<id>.action.yaml. |
content | string | required | No description |
reason | string | required | One line saying why, recorded in the audit log. |
expectedVersion | string | optional | The version returned by readAppFile or listAppFiles for the bytes you last saw. |
Scopes
apps:invoke, apps:write
Annotations
- Read only: no
- Destructive: no
When to use
Use writeAppFile to create a file, or to replace all of a file. To change one passage, use editAppFile: it is safer.
The tool needs the same access as listAppFiles: the scopes apps:invoke and apps:write, an admin or staff user, and manage access on the app. There is no confirmation step for the source tools. The change is made when the call succeeds.
- To create a file, omit
expectedVersion. The call is refused if a file already exists atpath. - To replace a file, call
readAppFilefirst and pass itsversionasexpectedVersion. The call is refused if the file changed after your read. contentis the complete new text of the file. Allowed file types are.md,.html,.css,.js,.sql,.yaml,.yml,.json,.txtand.svg. A file is at most 1 MiB. A package holds at most 64 files and 1 MiB in total.reasonis one line, 1 to 100 characters, that says why. It goes in the audit log with the file versions, not the content.- The change is live at once. There is no draft, no preview and no undo.
- Do not edit a migration that this instance has already applied. Add a new
migrations/NNN-*.sqlfile, and changeschema.sqlso that replaying every migration gives the same schema.
The result has version (the new version of the file), created (true for a new file) and status. A write that passes the path, size and version checks always lands, even when it breaks the app. Then status.ok is false and status.diagnostics says what to fix. The app cannot be used until you fix each diagnostic. When status.ok is true, the app is live at status.revision.
If the call returns an error, the change can still have landed. Call readAppFile before you retry.
Example
A new migration that adds a column:
{
"app": "timesheet",
"path": "migrations/002-add-billable.sql",
"content": "ALTER TABLE entries ADD COLUMN billable INTEGER NOT NULL DEFAULT 1;\n",
"reason": "Record whether time on an entry is billable"
}
The structured result (structuredContent). The app does not validate yet, because replaying the migrations now gives a column that schema.sql does not have:
{
"app": "timesheet",
"path": "migrations/002-add-billable.sql",
"version": "cd0aa9856147b6c5b4ff2b7dfee5da20aa38253099ef1b4a64aced233c9afe29",
"created": true,
"status": {
"ok": false,
"revision": null,
"diagnostics": [
{ "file": "schema.sql", "code": "APP_MIGRATION_FAILED", "reason": "replay_mismatch" }
]
}
}
The text part of the result says Created migrations/002-add-billable.sql (version …)., then lists each problem as <file>:<line> <code> <reason> and says to fix the named file and call checkApp. The next step here is editAppFile on schema.sql.
Refusals and what to do
The error result's text is the message. structuredContent.error holds code, message, retryable and diagnosticId.
APP_SOURCE_CONFLICT: the message says that the file changed after it was read, or that the file to create already exists. CallreadAppFile(orlistAppFiles) again, check the current text, and retry with the newversion.APP_SOURCE_FILE_INVALID: the file type is not allowed. The message lists the allowed extensions.APP_PATH_INVALID(app_path_invalid): the path is not a valid package path, for example it has more than four segments, a segment that starts with., or...APP_RESOURCE_LIMIT(app_resource_limit): the file is larger than 1 MiB, or the change would take the package past 64 files or 1 MiB in total. Make the file smaller, or delete a file you do not need.APP_INPUT_INVALID(app_input_invalid): the arguments do not match the schema. Examples: an emptyreason, areasonlonger than 100 characters or with a control character, anexpectedVersionthat is not 64 hex characters, or an extra argument.APP_ACCESS_DENIED(app_access_denied): this person does not havemanageaccess on the app, or is not an admin or staff user. An app id that does not exist gets the same answer.- If the connection does not hold both
apps:invokeandapps:write, the tool is not in your tool list, and a call to it returnsMCP error -32602: Tool writeAppFile not found. Read thepermissionssection ofgetDocs. The person must reconnect, or mint a new token, withapps:write. Only admin and staff can hold it.
Related
readAppFilegives theversionto pass asexpectedVersion.editAppFilechanges one passage.deleteAppFileremoves a file.listAppFilesandcheckAppshow the package status.