Summary#
var a = "line one\nline two"; // escapes processed
var b = @"C:\temp\report.csv"; // no escapes; "" is a literal quote; may span lines
var c = """He said "yes" and left."""; // no escapes; quotes written plainlyPick by what the text contains. Escapes are convenient until the text is full of backslashes; then @"…" is
clearer. Both get awkward once the text is a paragraph — which is what the raw form is for.
Signature#
| form | escapes | quotes inside | spans lines |
|---|---|---|---|
"…" | processed (\n, \t, \\, \", \uXXXX) | \" | no |
@"…" | none | "" | yes, verbatim — every leading space is kept |
"""…""" | none | written plainly | yes, and the closing delimiter's indentation is stripped |
Description#
The raw form, single line#
Everything between the delimiters, exactly:
var q = """He said "yes" and left."""; // He said "yes" and left.Open with more than three quotes when the text itself contains three:
var fence = """"a ``` and a """ inside"""";The rule is that the closing delimiter is at least as long as the opening one, so the author picks a fence longer than anything inside. Same as C#.
The raw form, multi-line — and the indentation rule#
Put nothing but whitespace after the opening delimiter and the literal becomes multi-line. Then:
- the first newline and the last newline are not part of the value;
- the closing delimiter's indentation is stripped from every line.
That second rule is the whole reason the form exists. It lets a block of prose sit at the indentation of the code around it while none of that indentation reaches the value:
agent Auditor {
Prompt = """
You review expense claims.
Meals are reimbursable up to 60 per person per day.
""";
}The value is You review expense claims.\n\nMeals are reimbursable up to 60 per person per day. — no leading spaces,
no blank first line, no trailing newline. Written as @"…" the same block would carry four spaces on every line
into the value, and written as concatenated "…" fragments it would not be readable as prose at all.
⚠ A line indented LESS than the closing delimiter is a compile error, not a partial strip. The alternative is a value whose leading whitespace depends on where in the file it was written, which nothing downstream could report. Line the text up with the closing delimiter, or move the delimiter left.
⚑ A blank line is exempt. It has no indentation to disagree with, and requiring some would mean trailing spaces on every empty line of a paragraph.
Why raw literals matter most for a prompt#
An agent's Prompt is the clearest case: it is prose, it is inherently multi-line, and it is the most
important text on the declaration. The instructions a model actually receives should be readable in the source that
supplies them.
Examples#
A multi-line prompt, and a verbatim path, in one app:
entity Note {
[Required, MaxLength(4000)] string Body;
security { allow read, create, update when IsAuthenticated; }
}
/// The multi-line raw form: indented with the code, and none of that indentation is in the value.
string Guidance() {
return """
Keep a note short.
A note that needs headings is a document, and belongs somewhere else.
""";
}
/// The single-line raw form — quotes written plainly, no escaping.
string Quoted() {
return """She said "no" twice.""";
}
/// Verbatim: no escapes, so a backslash is a backslash.
string ExportPath() {
return @"C:\exports\notes.csv";
}See also#
- Every type, in one list — every built-in type in one list
- Constant expressions — where a compile-time constant is required
- the agent loop (app.Agent, Loop) — the multi-line prompt this form was built for