Command line reference
Every flag of both commands, both exit code tables, and how to read what comes back. The narrative version, with the reasoning, is on the CLI and CI page.
Two commands
chrono run starts an application at a different date and time.
chrono calc works out a date and tells you what makes it interesting.
They share one step grammar, so a shift written for one means the same in the other.
chrono version answers a third and much smaller question: which build this
is, which of the two cores the executable is, and the protocol version it speaks. One
line on stdout, so a script can capture it.
chrono run <target> [options] chrono calc [options] chrono version # chrono 0.1.0 (x64, protocol 1) chrono --help # usage for all of them
chrono run - options
| Flag | What it does |
|---|---|
--at <moment> |
The moment to start at, in the session zone. Absolute
(2038-01-19T03:14:07) or relative with a leading sign
(+1d, -2h). Units: s m h d w mo q y -
m is minutes and mo is months. Without
this flag the session clock starts at the real current time, so --mode xN
on its own simply runs the target faster. |
--zone +HH:MM |
The session zone: the zone the moment is written in, and the one the target's local-time calls report. A fixed offset, with no daylight saving. Without it, the host's own zone. |
--mode flow|frozen|xN |
flow runs at real speed, frozen holds the clock still,
xN runs it N times faster (x60 turns an hour into a
minute, x1440 a day). |
--scale-duration |
Also speed up the duration axis: tick counts, sleeps and timers. Off by default, because a wall clock and a stopwatch are different questions. |
--scale-qpc |
Also scale the high-resolution counter, which is where Python 3.13+
monotonic, .NET Stopwatch and Java nanoTime
read elapsed time. Off by default: an application that times its rendering off that
counter can look distorted. |
--ticks N |
End the session after N heartbeats, one real second each, and report. Without it the tool stays attached until the target exits. |
--timeout <s> |
Give up after this many seconds and exit 6, for a pipeline that must not hang. Independently of this flag, a core that says nothing for 15 seconds is stopped and also exits 6 - in both cases the run is cut short, so it carries no verdict. |
--args "..." |
Arguments for the target, as one string, split by the same rule Windows uses - so
an argument containing spaces survives. For a Chromium target,
--user-data-dir and --remote-debugging-port are refused
rather than overridden: the session needs its own isolated profile, and quietly
running on your real browser profile is the one thing that must not happen. |
--cwd <dir> |
Start the target in that directory. Without it the target inherits ours, which is
what every run did before this flag existed. An empty value is a usage error rather
than "no directory" - absent and empty are different things, and only absent is
something Windows can be given. A directory that does not exist stops the session
with target.cwd_missing before anything is launched, instead of
surfacing later as a target that would not start. |
--preset <id> |
Take the moment and the speed from presets/<id>.json. Exclusive
with --at, --mode and --scale-duration, since
the preset is then the single source of both. |
--param id=value |
Fill a preset parameter. Repeatable, requires --preset. In
run only, a trial start date defaults to the target executable's own
creation date, so a trial preset counts from the day the application was installed
without you typing it. |
--set-after T:M |
At heartbeat T, change the speed to M. In flight the multiplier is at least 1 - freezing mid-session is not offered here. |
--jump-after T:moment |
At heartbeat T, jump the clock to that moment, absolute or relative, in the session zone. |
--force |
Keep the session even when the opening verdict says the substitution did not take effect - by default the target is stopped instead, because a session that proved nothing is worse than no session. The verdict does not change, and neither does the exit code. This only decides whether the target keeps running. |
--report <path> |
Write the human report to a file. A verdict other than works leads that file with an unreliable-evidence banner, because evidence that hides its own doubt is worse than none. |
--json |
Emit the session as machine-readable records instead of the report - the same stream the window itself consumes. |
chrono run - exit codes
The exit code is the session verdict, not what the application returned. The application's own exit code is reported separately, in the report and in the session data - the CLI and CI page explains why round that way.
| Code | Meaning |
|---|---|
| 0 | works - every process that read time saw the session clock |
| 10 | works partially - some channels covered, some not |
| 11 | does not work - the substitution did not reach the key channels |
| 4 | undetermined - coverage could not be established. An honest "cannot tell", never a pretended pass |
| 12 | the target vanished right after injection, which suggests a single-instance application handing over to a copy already running |
| 1 | usage error - a bad flag, a bad expression, or a preset this command will not accept |
| 2 | the target could not be launched or injected |
| 3 | internal error - the engine could not start or hit an unexpected state |
| 5 | the operation is not built in this release - for example a preset whose moment needs a calendar, which run cannot load yet. Deliberately distinct from a usage error: you asked for something that does not exist yet, not for something wrong |
| 6 | the run was cut short - --timeout expired, or the engine stopped answering for 15 seconds and was stopped. This is not a verdict: the session was interrupted, so it proves nothing about the target either way |
Reading the report
Without --json the session ends in a plain report. Every line is either a
fact the session observed or absent - nothing is filled in with a plausible default.
Chrono Mock - session report
target: .\build\test.exe
verdict: WORKS - time substitution took effect (processes: 1)
every process that read time saw the session clock
session: fake clock reached 2038-01-19T03:14:08
real elapsed 1.3s, fake elapsed 1.3s
exited: the target closed itself with code 3
covered channels (substituted, with call counts):
- pid 21240: GetSystemTimeAsFileTime (5 calls)
- pid 21240: GetLocalTime (5 calls)
observed channels (hooked but left real):
- pid 21240: NtCreateUserProcess (0 calls)
warnings:
- the target opened a network connection ...
- verdict - the family verdict over the parent and every child process, with the process count. This is the number the exit code carries.
- exited - the application's own exit code, and only when it
closed itself. A run bounded by
--ticksleaves the target running, a Chromium session is one the tool closes itself, and a session that never started has no such code - the line is then absent rather than showing a made-up zero. A crash code arrives as a large negative number, so it also gets its hexadecimal form. - covered - channels the substitution reached, with how many times each was actually called, per process. Counts are never summed across processes: one process's audit must not borrow another's numbers.
- observed - channels hooked but deliberately left real, such as object waits and multimedia timers. Their own bucket, so they are never read as substituted.
- uncovered - channels the application asked for and the session did not cover. This is what turns a verdict into partially.
- not fully cleaned up - anything teardown could not remove. Absent on a clean end, which is the normal case.
chrono calc - options
No natural language: each flag is one step, and the order of the flags is the order of the steps. The result after every step is printed, so a wrong step is visible rather than buried.
| Flag | What it does |
|---|---|
--base today|now|<moment> |
Where to start, default today. Resolved in the session zone. An
impossible day such as 2025-02-31 is refused, never quietly
normalised into the next month. |
--shift ±N<unit> |
Repeatable. The sign is required. Units: s m h d w mo q y bd, or
their full names. m is minutes, mo is
months. Months, quarters and years fold onto the calendar date with a
clamp, so a month after 31 January is the end of February, not a fixed number of
ticks. bd (business days) needs --calendar. |
--set-time HH:MM:SS | Set the time of day on the current result. |
--snap <target> |
Jump to a period boundary: som eom soq eoq soy eoy (start or end of
month, quarter, year). A start is the first day at 00:00:00, an end the last day at
23:59:59. |
--nearest nbd|pbd |
The nearest business day forward or back, the current day included when it already
is one. Needs --calendar. |
--to-zone +HH:MM |
A step: re-express the same instant in another fixed offset. The instant
is preserved, so the epoch value does not move and only the civil fields do. Not to
be confused with --zone. |
--zone +HH:MM |
The session zone, used to resolve today and now and to
render the result. Without it, the host's zone. |
--calendar us-banking|us-federal|pl |
Load a holiday calendar. It adds business day and holiday to the metadata and
enables bd and --nearest. The two American calendars differ
in how they observe a holiday falling at a weekend, which is exactly the kind of
off-by-one day a test is meant to find. |
--preset <id> --param id=value |
A named moment from presets/<id>.json, with its parameters
filled in. Exclusive with the step flags and with --analyze, and it
composes with --calendar, --zone and
--format. |
--analyze <date> |
Read a pasted date back and say what it is. An ambiguous 04/08 is
shown in both readings, American and Polish, rather than guessed -
that ambiguity is a real source of wrong bug reports. |
--format <mask> |
Print the result in your own mask as well, so it matches the format of the
application under test: yyyy-MM-dd HH:mm:ss. Tokens are case sensitive
in the .NET and Java sense - M is month, m is
minute. |
--json |
Machine output (chronomock.calc/1) for any of the above, so a pipeline
can compute a date and feed it straight back into chrono run. |
# Last business day of the quarter, American banking calendar chrono calc --base today --snap eoq --nearest pbd --calendar us-banking
chrono calc - exit codes
A separate, smaller table: the calculator has no coverage verdict to report.
| Code | Meaning |
|---|---|
| 0 | computed |
| 1 | usage error - a bad flag, an impossible date, a range overflow, or a calendar file with no business day in it |
| 5 | the step or unit is not built in this release, or the step needs a calendar you did not pass. Separate from a usage error on purpose, so a script can tell "not yet" from "wrong" |