Workspace and code
The conversation's working tree, how files are read and edited, and the calculator and code sandbox.
Every conversation has a working tree the portal owns. The six file tools reach it directly and run_code mounts it on every call, so a file an earlier turn wrote is there to be changed rather than written again. A deck’s HTML lives here — which is what makes editing one slide an edit rather than a second deck.
Key rules
- Files are portal records, not sandbox state. Listing a folder invokes nothing; every run names what it created, modified or deleted.
- Edit, don’t rewrite. Replacing a long file whole is refused and points to
edit_file. - A failed edit changes nothing. The refusal says where to look instead.
- One writer at a time. Writes take a lock per conversation.
- The workspace is temporary. What should last is saved as an artifact.
The workspace
Tools: list_files, search_files, read_file, write_file, edit_file, delete_file, plus run_code.
- Locking. A write takes a lock keyed by the conversation, because two programs changing one tree would answer differently depending on which finished first. The lock is a lease extended while the work runs, so a long sandbox run does not lose it halfway through.
- Paths. Paths are relative to the workspace root. The code sandbox sees the same tree one level down at
workspace/, sodeck.htmlandworkspace/deck.htmlare one file. File tools take the first spelling and refuse the second, naming the path the caller meant. - Safety on unreadable trees. A run that leaves the sandbox unable to report its tree changes nothing — an unreadable tree and an empty one would otherwise look the same, and the second deletes everything.
- Limits. A workspace is bounded by a byte count and a file count. A write past either is refused whole, counting the whole batch, so a call that cannot fit stores nothing.
- Lifetime. The workspace is removed when the conversation is deleted, and restoring the conversation does not bring it back. What is meant to last is the artifact, which carries the source that produced it. See Data lifecycle.
Writing files
write_file takes path and exactly one of content or source for one file, or a files array for up to three.
- A batch must be a real array, not JSON inside a string. Valid encoded batches are decoded before validation; malformed JSON is refused with instructions to use the direct fields.
- Use
sourcefor direct text exports from a stored tool result (Tool rules); userun_codewithtoolResultsrefs when transforming data.
Whole-file replacement guard
Replacing a file whole is refused once it has grown past a few thousand characters, and the refusal names edit_file. A document rewritten to change one value loses the parts nobody asked about.
- Deleting that file is then refused for the rest of the turn too — deleting and rewriting from memory is the same rewrite one call later.
- The guard reads the turn’s own trace: a failed
write_filenaming the path, over a file still long enough for the first refusal to stand. - A file nothing in the turn tried to write is deleted as usual.
- To replace a document outright, make one edit naming line 1 through its last line — which requires reading it first.
Editing files
An edit names what it replaces by text or by line; one call uses one of the two.
- The excerpt is copied from the file and must occur exactly once.
- Matching runs on the file with one newline style everywhere and no byte-order mark, because that is the file the caller was shown.
- The file’s own line ending is written back afterwards.
- Cheapest for changing a short value.
- A numbered range from
read_fileis replaced. - The caller repeats the range’s first line, so a range that shifted under an earlier edit is refused rather than applied elsewhere.
- Every range in one call is numbered against the file as it arrived; no two may overlap.
- Each change comes back with the line it now sits on, after the call’s other edits landed.
- Cheapest for a long block: you pay for the replacement alone.
When an edit is refused
A failed edit changes nothing, so a model working from a stale copy is told to read the file again instead of quietly writing a different document. The refusal says where to look:
| Problem | The refusal answers with |
|---|---|
| Excerpt matches nothing | The line numbers its first line does sit on |
| Anchor line has moved | What is there now, and where that text sits instead |
| Caller repeated the range’s last line | That fact — re-reading will not cure it |
| Overlapping ranges | Refused before any anchor is checked, so the caller learns the fault re-reading cannot fix |
Line counting
Lines are counted the way an editor counts them: a closing newline ends the last line rather than starting an empty one, and the newline belongs to no line. An edit writes back the newline the file already used, so changing one line of a CRLF document leaves the rest alone.
Reading and searching files
read_file
- Numbers the lines it returns and takes the same
startLineandendLinean edit takes — one pair of numbers for finding and changing. - One call spends a single character budget across every path, and each path has its own line cap.
- A cut-short file returns the next line to ask for and which cap hit: characters means lines are long (narrow the range); lines means the file is long (read on).
- An image file returns the picture itself, reduced to what a model is actually sent. A model that cannot see is told in words that the picture was left out.
search_files
- Finds literal strings across the tree and returns each match’s path, line number, the query that found it and, on request, up to three lines either side.
- Up to five strings per call, in one pass over each file — a second call would cost a model round trip of about 25 seconds.
- Queries are text, not patterns: a model-written pattern would run an untimed regex on the request thread.
- A long matching line is centred on the match. Context lines never repeat within a file (two hits three lines apart read as one stretch) and count against the same character budget.
Both workspace reads keep their exact text in context, because shortening lines an edit must match would leave the model guessing. Other large results use the preview. In a result carrying an image, only the text parts are shortened.
Trimming written documents from replay
A write’s arguments stay in the message list and would be resent at every later step. So a document a turn has already written is trimmed from the replayed call to its first 200 characters — enough to name it. The content lives in the workspace or the saved artifact. A call that failed keeps its arguments whole, because the model is about to work out what was wrong.
Arithmetic
The calculator is a parser written for the portal, because handing a model’s string to an evaluator is a remote code execution route.
| Accepted | Refused |
|---|---|
| Decimal and scientific numbers, four operators, exponentiation, parentheses, unary minus, minimum, maximum, absolute value, square root, rounding | Variables, assignment, state between expressions, a percent operator |
Answers are rounded to 12 significant digits, inside the precision of the portal’s money columns. Division by zero is a failed entry with a reason.
Running code
For a total over a file, the model writes Python against a filename, and the code reads bytes the model never typed. The default shape mounts the uploaded file; the other shape gives the passages in order. The description says to print a figure or a small table, not the data.
The sandbox
- Runs in the customer’s AWS account with no network, no credentials and no package installation.
- One session per call; nothing carries over to the next.
- Every id is resolved against the turn’s knowledge bindings and the caller’s collection before a byte is read.
- The runtime holds no AWS credentials or SDK and calls one portal route over HTTP.
- A traceback returns to the model verbatim, because the model wrote the code.
Workspace effects
- The workspace is mounted on every call. What the code leaves is kept and reported as files created, modified or deleted; a file it removes is removed.
- A run that raised keeps its changes too — a half-written file is left for the next call to repair.
- Saving one of those files as an artifact is a separate step. The stored copy belongs to the person whose turn it is and is billed to their department.
Existing artifacts as inputs
- A file artifact can be handed to the code, which is how a spreadsheet or document is changed rather than rewritten. Access follows the artifact’s own sharing rules, not the conversation — an uploaded file belongs to no conversation. Changing it means reading it, writing the changed file, and adding it to the same artifact as a new version. Find-and-replace over a stored file is refused: there is no text to match.
- Text artifacts can be mounted by id and optional version under
inputs/artifacts/followed by the id, with.mdfor documents,.jsonfor charts,.htmlfor web previews and.txtfor other text kinds. The artifact’s sharing rules authorise these reads.
Stored results as inputs
run_code accepts up to three toolResults refs. The backend mounts the complete stored outputs in order at inputs/tool-results/1.json, 2.json and 3.json; each holds ref, toolName, isError and output. Code can extract fields and write a deliverable to workspace/ without paging the source through the model.
- Refs use the same conversation boundary and count toward the run’s total input byte limit.
- A stored result may represent only one page of an external API; mounting preserves exactly what that call returned.
Skill files
A skill can ship files of its own. Loading the skill lists them by path and size, without the bytes; naming the skill in a code run mounts them under a directory named after the skill, so instructions referring to a script beside them are true. Which skills may be named is the same test the skill loader applies, derived from the turn. A bundle past the deployment’s size limit is refused whole.
Every tool route
Before its own work, every tool route answers four questions: whose turn this is, whether the turn may reach that tool, who the caller is, and what the trace should say. The tool name answers the second and fourth, because the catalogue records the kind of step each tool writes. A turn calling a tool it was never offered is refused, naming the tool and disclosing nothing else.