editAppFile
Replace one exact passage in a source file of a Sasha App you manage
Replace exactly one occurrence of oldString with newString. oldString must match the current file exactly and occur exactly once, otherwise the edit is refused rather than guessed. Always readAppFile first and pass its version. The change is LIVE immediately. 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. |
oldString | string | required | No description |
newString | string | required | No description |
reason | string | required | One line saying why, recorded in the audit log. |
expectedVersion | string | required | 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 editAppFile for most changes to an app: it changes only the passage you name. To create a file or replace all of it, use writeAppFile.
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.
- Call
readAppFilefor the file. Keep itsversion. - Call
editAppFilewitholdStringcopied exactly from the current text,newString, a one-linereason(1 to 100 characters, recorded in the audit log), and theversionasexpectedVersion.
Rules:
oldStringmust match the current file exactly and occur exactly once. If not, the edit is refused. It is never guessed. Include more of the surrounding text to make it unique.newStringcan be empty, to remove the passage. It must not be the same asoldString.expectedVersionis required.- The change is live at once. There is no draft and no undo.
The result has the new version of the file and status. An edit that passes the checks always lands, even when it breaks the app. Then status.ok is false and status.diagnostics says what to fix. 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
Add the billable column to schema.sql, after a migration added it:
{
"app": "timesheet",
"path": "schema.sql",
"oldString": " note TEXT\n);",
"newString": " note TEXT,\n billable INTEGER NOT NULL DEFAULT 1\n);",
"reason": "Match schema.sql to migration 002",
"expectedVersion": "3f79bb7b435b05321651daefd374cdc681dc06faa65e374e38337b88ca046dea"
}
The structured result (structuredContent):
{
"app": "timesheet",
"path": "schema.sql",
"version": "aaa9402664f1a41f40ebbc52c9993eb66aeb366602958fdfaa283b71e64db123",
"status": {
"ok": true,
"revision": "de7d1b721a1e0632b7cf04edf5032c8ecffa9f9a08492152b926f1a5a7e765d7",
"diagnostics": []
}
}
The text part of the result says Edited schema.sql (version …). and App validates. Live revision ….
Refusals and what to do
The error result's text is the message. structuredContent.error holds code, message, retryable and diagnosticId.
APP_SOURCE_MATCH_INVALID:oldStringdoes not occur in the current file, or occurs more than once. CallreadAppFile, and include more surrounding text so that the passage occurs exactly once.APP_SOURCE_CONFLICT: the file changed after you read it. CallreadAppFileagain, decide whether your change still applies to the new text, and retry with the newversion.APP_NOT_FOUND(app_not_found): there is no file at that path. To create a file, usewriteAppFilewithoutexpectedVersion.APP_INPUT_INVALID(app_input_invalid): the arguments do not match the schema, ornewStringis the same asoldString. Other examples: an emptyoldString, a missingexpectedVersion, anexpectedVersionthat is not 64 hex characters, or areasonthat is empty, longer than 100 characters or has a control character.APP_RESOURCE_LIMIT(app_resource_limit): the file would be larger than 1 MiB, or the package would go past 1 MiB in total.APP_SOURCE_FILE_INVALIDorAPP_PATH_INVALID(app_path_invalid): the path is not one that these tools can change. Use a path fromlistAppFiles.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 editAppFile 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 the text to copy and theversion.writeAppFilecreates a file or replaces all of it.checkAppvalidates the package after a set of edits.listAppFilesshows every file and the package status.