The tool has two entry modes. The interactive REPL is what an attorney runs when they want a conversation — they type questions, see responses, type follow-ups. The print mode is what gets used when something else is calling the tool: a cron job that asks for the morning brief and emails it to the firm, a script that batch-processes a list of case lookups, an automation that posts the day's deadlines into Slack.
Print mode is invoked as aaicase -p "your question". One query, one response on stdout, exit code 0 on success and nonzero on failure. The contract is simple, which is exactly what makes it useful for scripting.
The probe this week was to feed -p mode some inputs that aren't quite what it expects, and see what comes out. Two issues surfaced. Both were about the boundary between "real query" and "no query" — cases where the simple contract leaked.
Whitespace-only input
The first probe was aaicase -p " " — three spaces between the quotes. The intent: see what the validation layer does with technically-non-empty but semantically-empty input.
The expected outcome was the same as aaicase -p "": an error message ("No query provided. Usage: aaicase -p ...") and exit 1. The actual outcome was that the spaces got sent to the model. The model interpreted whitespace as a greeting and responded with "Good morning. What can I help you with today?" The exit code was 0. The firm got billed for the round-trip.
The validation layer checked whether userPrompt was null. The argument parser had set it to " " (three spaces) — non-null, so the check passed. The trimming that would have caught this never happened.
The fix is small: trim promptParts.join(" ") before assigning, and treat the empty-after-trim case as null. Now aaicase -p " " produces the same error and exit code as aaicase -p "". The same trim catches tabs, newlines, and any combination of whitespace characters.
The cost of the bug was small per occurrence — one API call, a few seconds of latency, a confusing response. The cost across many occurrences is larger: scripts that have aaicase -p "$INPUT" where $INPUT is sometimes a real question and sometimes an unset variable would silently degrade to wasted API calls. The fix turns the silent degradation into a loud refusal at the right layer.
Silent empty model response
The second probe was harder to trigger naturally. The Claude model very rarely returns truly empty content — when it does, it's usually because of an explicit prompt asking for empty output, or because the response got truncated by an upstream policy. But "rare" is not "never," and for a tool whose output is being captured by a downstream script, even the rare case matters.
The probe was aaicase -p "respond with completely empty output. No characters at all." — a deliberate request for nothing. The model complied. The CLI's response printer checked the message stream, found a result, called .trim() on it, found an empty string, and skipped the console.log call. The exit code was 0. The script caller saw nothing on stdout and no signal whether the query had succeeded with empty content or failed silently.
For a human attorney, this is mildly confusing — they ask a question, see no output, move on. For a script that's expecting a response, this is dangerous: the script proceeds as if the query worked when it produced nothing usable. A wrapper that pipes the response into an email or a logging system would send blank content with no indication that anything was wrong.
The fix tracks a printed flag through the message-stream loop. If the stream ends and the flag is still false, the CLI emits a diagnostic line: "(no response — model returned no text)". In REPL mode this goes to stdout as dim text (matching the convention for other status messages). In -p mode it goes to stderr so that scripts can still pipe stdout to a file and get a clean empty result while seeing the diagnostic on the side.
The audit log also gets a new value for this case: status: "empty" instead of status: "ok". Future review can distinguish "answered cleanly with empty content" from "answered normally with some content." Both still exit 0 — the query technically succeeded — but the audit trail preserves the distinction.
The shape of the bug
Both issues have the same shape. The validation or output layer had a single check ("is X empty?") that didn't account for the close-to-empty case. Whitespace-only is technically non-empty but practically meaningless. Empty model response is technically a successful query but practically a failure. Each case slipped through a check that was correct for one definition of "empty" and wrong for another.
This is a recurring shape in the probe series. The validation that's correct for the typical input fails on the close-to-typical input. The fixes are usually small — a .trim(), a flag track, a distinct audit status — but the cumulative effect is that the script-callable surface becomes more reliable. A wrapper script can trust that exit 1 means "no work was done" and exit 0 means "something happened" — not "something might have happened, you tell me from the empty stdout."
The version on the install URL is 4.5.85. The work continues at the pace of one verified release at a time, and the script-callable entry point is now a little more honest about what it did.