the refusals
cr8script's premise is unfashionable: a language whose refusals are the feature. It refuses Python's silent type coercion, refuses truthy/falsy, refuses null, refuses 0-based lists. Each refusal trades convenience for the property that matters most when a model writes the code — that the script either does what it claims, or fails in a way the model can fix.
no truthy/falsy
In Python, if 0 is false, if "" is false,
if [] is false. Each is a quiet little surprise the
language hopes you'll appreciate. For an LLM writing one-shot
scripts, this is exactly the wrong default: a typo that makes
the test reach an empty list silently passes the wrong branch and
runs to completion with the wrong answer. cr8script makes
if 0 then a located error — the model
sees the line, sees the value, knows what to fix.
The cost is one extra character in some places: if
xs.length is greater than 0 instead of if xs.
The benefit is the entire class of "I thought it was a list, it
was empty" bugs disappearing.
no silent type mixing
Languages disagree about "5" + 3. JavaScript says
"53". Python says TypeError. cr8script
says error, on this line, with this value, with the fix:
use to_text(3) or to_number("5"). The
explicit cast is two seconds; the bug it prevents is
indeterminate — particularly when a number arrives as a
string from an HTTP response or a CSV cell.
Crucially this also covers cross-type equality. 5 is
"5" isn't false — it's an error. The
language refuses to decide whether the string and the number are
the same; the writer has to decide.
decimal by default
Every reader who has ever written a quick "what's the total?"
script in Python has seen
0.30000000000000004 appear in a place a human will
read. It's float arithmetic; it's correct; it's also wrong for
the use case. cr8script's number type is decimal. There is no
float. There is no Decimal import. There
is just number, and addition does what you wrote.
The cost is a tree-walking evaluator that's slower at scientific computing. cr8script doesn't do scientific computing. The benefit is that finance, billing, tax, and reporting scripts — exactly the kind a model writes that a human reads and trusts directly — produce the number on the page, not a number eight ulps away from it.
1-based lists
This is the most opinionated choice and the one most likely to
irritate a reader who has indexed from zero their entire
career. The argument: people writing one-shot data scripts almost
never want the C-array semantics that 0-based indexing was built
to support. They want "the first row", "the third item", "the
last entry". Most of the time the right access isn't an index at
all — it's xs.first, xs.last, or
a pipeline.
An LLM trained on a hundred languages will mis-index between them.
Making xs[0] a located error rather than a
silent off-by-one closes one of the most common silent-bug
surfaces in agent-written code. The migration cost is real; the
diagnostic when the model gets it wrong is immediate.
only nothing for absence
Python's None is the C++ pointer's grandchild — a single
sentinel that means absence, missing-ness, default, "I forgot",
"it didn't apply", "the call failed", "look it up later". JavaScript
has both null and undefined with subtly
different rules nobody remembers. cr8script collapses absence to
one keyword: nothing. Field access on a record
requires the field to exist; absence is opt-in via
r.get("key"), which returns nothing on
miss.
The single sentinel makes "is this missing?" a single
check (x is nothing) rather than three different
ones across libraries. The required field access prevents a typo
in r.cusomer from silently returning
None — it's a hard error with a "did you mean
customer?" hint.
errors that teach
Most language error messages were designed for the human at a
terminal. cr8script's were designed for the agent in a tool-use
loop. Every diagnostic carries three things: the line
where the problem is, a message describing what went
wrong, and a hint proposing a concrete fix. The static
checker emits these as JSON via --check-json —
a list of {line, message, hint} objects the model
reads and acts on without parsing English error text.
This is the property that justifies the rest. The refusals (truthy/falsy, type mixing, indexing, null) only pay off if the moment of failure is converted into something the writer can fix. cr8script's wager is that a small language with strict semantics and structured diagnostics produces fewer bugs per token than a permissive language with loose semantics and free-form English errors.