Skip to main content
DeckTalk answers in codes. Every error code and every finding code carries its own page, and this page is the map from what you saw to which code it was. Each code’s page carries its sentence, its severity and the settings keys that move it. They are generated from the same enums the tool prints from, so they are the authority on what a code means. This page is the other half: what the symptom looks like, which command to run to make the code appear as data, and what to change.

The two kinds of answer

An error means DeckTalk could not run, so nothing was judged. It prints one block and the command stops.
A finding is a judgement DeckTalk made about your files or your film. The command ran, and this is what it measured. It prints its own sentences, then one line per judgement, then one count line.
The line opens with the file and the line number when the finding knows them, and with the object it judges when it does not. The fix line under it appears only when the finding carries one. Under --json, error is filled for the first and null for the second, and findings carries the second as an array of objects. An error exits 2 or 3, or 130 when the run was interrupted, and a finding at or above the threshold exits 1. Exit codes, Error codes and Finding codes list all of them in one place.

The three commands to run first

None of the three produces a film and none of them spends. decktalk check --no-pages goes further and opens no browser at all, which makes it the one to run on a machine with no Chromium and inside a commit hook. It names every judgement it could not reach rather than passing quietly.
decktalk check --no-frames keeps the browser and drops the freeze comparison, which is the faster half when you only want the reading of the files and the page.

Apply the fix a finding carries

A finding may carry a fix. It is one of three kinds, and it declares how far it may be trusted. decktalk check --fix, decktalk doctor --fix and decktalk build --fix apply every safe fix and print every other one. --no-fix applies none. In the library it is Project.apply(finding, unsafe=False), and passing unsafe=True is the only way an unsafe fix is ever written. The count line tells you before you run it: Found 1 finding, 1 error. 1 fixable with --fix. A safe fix does the boring part and leaves the judgement to you. check --fix on a project with no cue file writes every row the deck declares with an empty phrase, so the next check reports a CUE_UNRESOLVED for each empty phrase and a build stops at cue on them. That is the fix working. Fill in the phrases and run it again.

Carry on past a code, or change what fails a run

--allow CODE carries on past one code, and --fail-on chooses which severity fails a run. Which findings fail a run is the table of both. build also stops on what fails it. When a stage inside a build judges something at the --fail-on threshold, the build stops after that stage rather than carry the finding into the film, because a film that is wrong in a way nobody has to watch it to discover is not worth recording. The stages it did not reach are reported as skipped, and the run still returns everything it knows: it exits 1, its findings are printed and in the JSON, the money narrate already spent is in cost, and stopped_at names the stage it stopped after.
The three TAKE_MISSING lines are warnings, so they do not stop the build. The one error does. The two flags that decide what fails a run decide what stops a build, because a build that carried on past a finding its exit fails on would spend on a film already called wrong.
  • --allow CODE carries the build past that code, and it works for every code. The finding is still printed and still in the JSON, and it no longer stops the build or counts toward the exit.
  • --fail-on warning stops on a warning as well, and --fail-on never runs every stage whatever it finds.
verify is the last stage, so its findings end a build rather than stop it. Reach for --allow only for a code you mean to keep, and say why, because the film it lets through carries that finding. A cue a deck under construction has not drawn yet is the usual case:

From a symptom to a code

Every code links to its own page, which carries that code’s sentence, its severity and the settings keys that move it. The rest of this page says what to change.

A missing toolchain

DeckTalk needs Chromium to record a page and ffmpeg with ffprobe to measure, cut and encode. It fetches both the first time a command needs them and keeps them in a per-user cache. What you see. error[TOOL] when a command needed one of them and could not run it, or a FILE_MISSING finding from doctor for each component this machine has not got. What to do.
  1. Run decktalk doctor. It prints a row per component with its version and where it came from. On a terminal it then offers once to fetch what is missing, and with --no-input and no --fix it fetches nothing.
  2. Run decktalk install, or decktalk doctor --fix, which applies the safe command fix that each FILE_MISSING carries. Both fetch the toolchain up front rather than in the middle of a build.
  3. On Linux, decktalk install also asks Playwright for Chromium’s system libraries, which it installs through sudo, so it may ask for a password. A build never does that, because a build runs unattended and a password prompt is a hang rather than a question. That is why a Chromium that will not launch says to run decktalk install.
  4. A download that stalls stops with error[TOOL] saying how much of ffmpeg arrived and that the next run resumes from there. Run decktalk install again: it asks for the rest rather than the whole archive, and checks the pinned SHA-256 on all of it. On a link too slow to finish, set tools.ffmpeg and tools.ffprobe to a build you already have.
The settings. tools.ffmpeg and tools.ffprobe name binaries the machine already has. tools.cache_dir moves what DeckTalk fetches, Chromium and ffmpeg together. tools.chromium records with a browser the machine already has and skips the Chromium download entirely. All four are machine keys, so set them with decktalk config set KEY VALUE --scope machine, because a decktalk.toml that sets one is refused. Set PLAYWRIGHT_DOWNLOAD_HOST to a mirror when a proxy blocks Playwright’s own host, and set tools.cache_dir when the home directory is read-only or the browser is shared. FILE_MISSING is also what a stage raises when a file the project names is not on disk, such as an audio file of your own that a [[mix.effect]] row cues or a clip a section names. There the fix is to write the file or correct the path. A sound the score describes and has not bought yet is SOUND_MISSING instead, a warning that plays silence in its place, and decktalk score --spend buys it.

An input error

What you see. error[INPUT], naming the file, the key or the argument and what is wrong with it. The command exits 3 and makes nothing. What to do. Correct what the message names and run the command again. The hint says where to look: the line of a decktalk.toml that is not valid TOML, or the sections there are when a --section names one that is not. A key that belongs to the machine, such as record.concurrency, is refused in decktalk.toml with this code, and the hint names the decktalk config set KEY VALUE --scope machine line that moves it. A program this machine does not allow is also INPUT: see A program the project names.

A refused command line

Exit 2 means DeckTalk refused before doing anything, and a retry of the same line is refused again. USAGE. The parser refused the line. The message names what is wrong with it. Run decktalk <command> --help, or decktalk schema for the whole instruction set as one JSON object. APPROVAL. A run that would spend money was not approved. narrate and score are the two stages that spend. A run with nothing to buy is never asked, so a project whose takes are all on disk builds with no flag and no key. --no-input never prompts. It takes the safe default, or it refuses and names the flag that would have answered, which is what makes a non-interactive run deterministic. APPROVAL also refuses four steps that are not a spend: init into a directory that holds files (pass --overwrite), a Chromium install whose system libraries need a password nobody gave, a run that may spend and would open an untrusted page (voice in a run of its own first), and a --max-cost that cannot price the run because nothing states the rate. Each hint names the command that approves it. In the library there is no terminal to ask, so nothing spends without spend=True, and ApprovalRequired is raised rather than money being spent.

A stage run before the one it reads

What you see. error[NOT_BUILT], naming the file that is not there and the command that writes it.
Each stage reads what an earlier stage wrote, so a stage run on its own before that one fails here. Run the command the hint names, or run decktalk build, which runs every stage in order. decktalk narrate --no-spend writes the takes without buying anything, with a placeholder wherever a take is missing. decktalk status names the next command to run.

A voice that did not answer

What you see. error[PROVIDER], with the HTTP status and the host when ElevenLabs answered, or the reason when it could not be reached. What to do.
  1. Read the status in the message. A 401 is a key ElevenLabs does not accept, and a 429 or a 5xx is ElevenLabs being busy, which a later run usually gets past.
  2. Run the same command again. Each take is written to the takes directory as soon as it is voiced, so the turns already voiced are found on disk and the run pays only for the rest. When the message says the request was possibly charged, its reply broke after it was sent, so check the account’s usage first: running again buys that take once more.
  3. A key that is not set at all is not this code. It is an INPUT error naming ELEVENLABS_API_KEY, raised before any request is sent.

A locked project

What you see. error[LOCKED], naming the process and the run that holds the directory, with the hint to wait for that run or stop it. One writing run at a time holds an operating system lock on build/.lock. While it holds it, build/.lock.owner names its process id and its run id. A second writing run is refused rather than allowed to overwrite the first one’s work. What to do.
  1. Find the run named in the message. It is usually a --watch build in another terminal.
  2. Let it finish, or stop it. The system releases the lock the moment the run ends, including when it is killed. The empty file stays in build/, and that is expected.
  3. A lock is never left behind by a process that is gone, because the lock belongs to the process and not to the file. When a killed run left build/.lock.owner behind, the next run takes the lock, prints a warning saying so, and carries on. Deleting the file is never needed.
  4. To read the project while a build is running, use decktalk status or decktalk check --no-pages. Neither writes, so neither takes the lock.
The same code names the take store when the message says another run has been voicing a take into it. Two projects on one machine that need the same take buy it once: the second waits for the first, and is refused when the wait passes one whole take request, every attempt narration.timeout_seconds long with the waits between narration.retries. Let the other run finish, then run this again, and it copies the take in rather than buying it.

An unresolved cue

A cue is one thing written in two files. The page declares a moment with a cue name, and cues.json carries its cue id, such as 4.1:expand, in its id field. Four codes say which half is missing. Reading CUE_UNRESOLVED. The message names the phrase and how many words the section actually speaks.
Run decktalk words --section 1 to see every spoken word with its start and its end, which is the clock a phrase is written against. Match the phrase to words that are really there. A phrase is matched without case by default, and the row’s own keys narrow it: occurrence picks which of several matches to take, case_sensitive makes the match exact, offset_seconds moves the second the cue fires, and verify set to false leaves the cue out of the measurement. Reading CUE_STALE. verify measures the film on disk against the cue times the last build placed. Edit cues.json and run verify alone, and the times no longer match the file:
The phrase is not the problem, so leave it alone. Run decktalk build. It places every cue again, records only the sections whose cue times moved, and keeps the rest. decktalk status names build as the next step for the same reason. Reading CUE_UNLISTED. This one carries a safe edit fix that writes a row per declared moment with an empty phrase for you to fill. On a cues.json laid out in a way DeckTalk cannot place a row into, the fix is display instead and prints the rows for you to paste. Reading CUE_UNKNOWN. When DeckTalk can see which cue the row was probably meant to be, it offers an unsafe rename fix, which is unsafe because renaming an id the author typed is a reading rather than a fact. --allow CUE_UNKNOWN carries a build past it, which is the usual choice for a deck under construction that lists the cues of slides nobody has drawn yet. Which command sees what. The cue stage compares cues.json against the catalog the page published into its recordings, so a section whose page has never been recorded is left unjudged rather than guessed at. decktalk check makes the same comparison against a page it opens live, which is why a fresh project shows CUE_UNLISTED and CUE_UNKNOWN from check and not from cue. CUE_OVERLAP is the neighbouring warning. It fires when two cues resolve close enough together that one motion is still playing when the next begins, and the message says how far apart they landed and how long the first was still running.

A picture that does not change

A cue that resolves to a second means nothing if nothing on screen moves at that second. Three codes measure that, all of them by comparing frames. What you see. The message carries the measured share of the frame and the floor it is under.
What to do.
  1. Look at the two frames the message names. decktalk check writes a frame either side of every cue under build/frames/, and draws them all onto build/storyboard.html.
  2. decktalk storyboard --before 1.1:title --after 1.1:title freezes just that pair, which is the fastest way to see what the reveal actually did.
  3. Make the reveal bigger. A reveal that changes a few pixels is a reveal a viewer misses too, so the usual fix is on the page rather than in the settings.
  4. Check the element really has a moment attribute and that its cue is the one that fired. An element that only changes class needs data-class, and a class change that animates needs the page’s own stylesheet to do the animating.
The settings. verify.changed_share_min_percent is the floor, as a percentage of the frame. verify.thin_change_factor is how many times that floor a change must cross to stop being thin. verify.probe_diff_luma is the per-pixel luma difference that counts a pixel as changed, and verify.probe_delays_seconds is when after the cue the frames are compared. video.crf moves all three, because a harder compression smooths away small changes before anything measures them. Read any of them whole with decktalk config explain verify.changed_share_min_percent.

A recording that opens black or runs short

These two are measured against a recording rather than against a file you wrote. record measures both on the file it has just written, and verify measures RECORD_BLACK again on the finished film. Where the black usually comes from. The recorder steps the section clock from second 0, and frame k is exactly what the page shows at second k / fps. A black frame is therefore a page that showed nothing visible at that second: a slide whose every element waits for a later cue, a background that is black on purpose, or a page that threw before it drew. There is no start to guess, so a black frame never moves the reveals around it. Where a frozen picture usually comes from. Something on the page threw, so whatever it drew stopped there while the recording carried on. The page reports that itself, through the probe, as one of these: What to do.
  1. Run decktalk serve and open the page in your own browser. It serves the deck directory and the files decktalk.toml declares, and nothing else, so what you see is what the recorder sees. A declared file is reached only by the spelling decktalk.toml gives it, on every platform, so a page that asks for it with other capitals is refused. Browser preview and recording says what the origin serves.
  2. Read the browser console. These seven codes are the page’s own report from the browser, so the detail behind each one is there.
  3. Run decktalk check, which opens the same page through the same probe without recording anything.
  4. For a truncation, record the section again with decktalk record --section N. A stepped recording holds one frame for every step of the section clock, so a short one is an encode that ended early rather than a page that was slow.

A recording that stopped at its deadline

What you see. error[TOOL] saying a page stopped answering, ran past its deadline, or that its renderer crashed. The message names the page and what it was doing when it stopped: a load, a step, a capture, a still or a report. record also names the section and the frame. Every call into a page is held to record.page_deadline_seconds, 15 seconds by default, which is many times the longest a step takes, so only a page that stopped answering reaches it. A recording as a whole is held to record.deadline_slowdown times what this machine’s measured record.chunk_startup_seconds and record.step_seconds say it should take, 30 times by default, so a page that answers every call and never gets on still stops. What to do.
  1. Look for a script that spins the page’s main thread, or a font or an image that never arrives. decktalk serve and the browser’s own tools show it.
  2. On a slow or loaded machine, raise record.page_deadline_seconds or record.deadline_slowdown with decktalk config set KEY VALUE --scope machine, or for one run with DECKTALK_RECORD_PAGE_DEADLINE_SECONDS and DECKTALK_RECORD_DEADLINE_SLOWDOWN.
  3. A chunk whose renderer crashed is recorded again in a fresh page, up to record.renderer_retries times, once by default, and gives the same frames, because a frame is a function of its index. A renderer is most often killed for memory, so lower record.concurrency when the crash repeats.

A late landing

The whole point of DeckTalk is that a picture arrives on its word. These codes are how it says a picture did not. What to do about CUE_OFF.
  1. Read the number in the message. It says how far off the change landed and what the limit is.
  2. A whole section that is late by the same amount is usually motion that keeps a clock of its own. The recorder steps every timer, animation frame and animation on the page, but not a Worker’s clock, so draw that motion from DeckTalk.frame with the region it draws in instead. A <video> or an <audio> is refused as PAGE_REALTIME_MEDIA before it can drift.
  3. One cue that is late on its own is usually a phrase that resolves to the wrong word. Run decktalk words and read what the section really says around it. Set occurrence on the row when the phrase repeats.
  4. offset_seconds on a cues.json row moves one cue by a fixed number of seconds. Use it when the picture genuinely belongs slightly before or after its phrase, and not to paper over a phrase that matched the wrong place.
  5. verify.cue_offset_max_ms is the limit, and verify.av_offset_max_ms is the audio against video limit beside it. Widening a limit hides the measurement rather than fixing the film.
When the motion itself is the problem. A cue can only be measured if the motion it starts is over quickly enough to be read as a step. The ceiling is half a second, and three codes report going past it. Something meant to move for longer than half a second is a motion or a loop rather than a moment. Declare it, and verify masks it out of every cue and measures its own departure and arrival, as Things that move shows. MOTION_OFF, MOTION_NO_EDGE and MOTION_MASK_LARGE are the codes it raises, and the findings gives the fix for each. How long a moment may move gives the range of data-in-seconds and data-stagger and the stagger’s arithmetic, and decktalk schema page prints every attribute with its range. motion.scale multiplies every declared length, so a value above one is what pushes a deck that was fine over the ceiling. CUT_SPEECH and CUT_POP are about the cuts rather than the reveals. A cut that slices a word means the section’s narration did not have room to finish, and narration.tail_seconds is the silence kept after the last word of a section so that a cut breathes. verify.cut_max_dbfs and verify.cut_window_seconds are how quiet, and for how long, a cut has to be to pass. CUT_POP is measured only where a section declares seamless = true, which is the promise that its picture continues the one before it. The last frame of the previous section and the first frame of this one are compared, and more than verify.cut_change_max_percent of the frame differing means the promise was not kept. Either make the two pictures actually continue, or drop the promise and let the boundary be an ordinary cut, which [transition] dips through.

A motion verify cannot measure

What you see. One of the motion codes: something on the page moves that nothing declared, a motion names a cue that never fires, or a declared motion lands away from its word. Everything that moves for longer than a moment is declared: data-motion or data-loop in the markup, DeckTalk.motion from a script, or DeckTalk.frame with the region it draws in. Verify masks what is declared out of every cue and measures a motion’s own departure and arrival. Footage belongs in a clip section, and a picture a program draws belongs in a render section. What verify does with each gives the measurement.

A loudness miss

What you see. MIX_LOUDNESS, which is a warning, with the measured numbers in the message. The mix is mastered to audio.target_lufs, with audio.true_peak_max_dbtp as the peak ceiling. The defaults are -16 LUFS and -1.5 dBTP, which are ordinary values for video on the web. audio.range_max_lu is the loudness range the measurement is made against, and no mix fails on it. Sound says exactly when MIX_LOUDNESS is raised. What to do.
  1. Check whether the loudness pass ran at all. On a build with placeholder narration it does not, and the run says so.
    Judge loudness on a voiced build.
  2. A film that misses the target by a lot usually has a bed fighting the voice. [mix] music_db, [mix] music_duck_db and [mix] ambience_db are where that is settled.
  3. Change the target only when you are mastering for a platform that asks for a different one. Read it whole first with decktalk config explain audio.target_lufs, which prints its range and the layer that set the value in force, and whose --json lists every layer that stated it.

A page that loads an asset from a network origin

What you see. PAGE_CDN_ASSET, once per other origin the page reached for, naming that origin.
It is an error and it carries no fix, because only you can decide what the local copy should be. What to do.
  1. Download the asset into deck/ and point the page at the local copy. A font, a stylesheet, a script and an image are all the same answer.
  2. For equations there is nothing to download. DeckTalk serves the packaged KaTeX at /__decktalk/katex/ on the page’s own origin, so a page that links those two files loads nothing from a network.
  3. Run decktalk serve and open the page. That origin serves the deck directory and the files decktalk.toml declares and nothing else, so anything the page still fetches from elsewhere is visible in the browser’s network panel.
  4. Keep the code if you mean it. --allow PAGE_CDN_ASSET carries a run past it, and it is worth writing down why, because a film that cannot be rebuilt in a year is what the code is warning about.

A sandbox that will not start

What you see. error[TOOL]: could not launch Chromium with its sandbox on, on a machine whose record.page_policy is untrusted. An untrusted page runs only inside Chromium’s sandbox, and a machine that cannot start it is refused rather than given a browser without one. The sandbox is a property of the machine, so no edit to the project clears this. What to do.
  1. In a Linux container, run the render as a user other than root, because Chromium refuses its sandbox to root.
  2. Give that container a seccomp profile that allows user namespaces. Docker’s default profile does not, and a render as an ordinary user under it is still refused.
  3. If the pages are your own work, the machine does not need the policy. trusted is the default, and decktalk config unset record.page_policy --scope machine returns to it.
Under untrusted, a request for another origin is refused rather than sent, so a page that loads a font or a library from a CDN renders without it. The run still names that host as PAGE_CDN_ASSET, and the fix is the one above: put the file beside the page. A page someone else wrote says what the policy does.

A program the project names

What you see. PROGRAM_NAMED from decktalk check, once for each program the project names, and error[INPUT] from build or record, before anything runs, when this machine does not allow it. A render section’s render_command is a program, and it runs with your user’s rights, so it can read every file you can, .env included. record.programs is the machine’s to set, and a project cannot allow its own programs: refuse, the default, runs none of them, ask runs them when a person at a terminal says yes, and run runs them without asking. Under the untrusted page policy no program runs whatever it says. What to do.
  1. Read the program the finding names before you allow it.
  2. Allow it for one run with decktalk build --no-spend --set record.programs=run, or with DECKTALK_RECORD_PROGRAMS=run in the environment.
  3. To be asked each run, run decktalk config set record.programs ask --scope machine.
Programs a project names says how far a program is trusted.

A page the contract refuses

These come out when check opens the page, and all but PAGE_NO_DESCRIPTION and PAGE_SWAP_APART also when record does and again when verify reads the recording log. Most of them the page reports about itself, through the probe, and the rest DeckTalk reads off the catalog the page published. All of them are about markup rather than about timing, so all of them can be cleared before a single credit is spent. One of them, PAGE_SWAP_APART, is a warning, and the rest are errors because the contract either declares a thing or it does not. What to do. Run decktalk schema page, which prints every attribute with their values, their defaults, their ranges and their spans. It is generated from contract.ts, the one home of every attribute, so it cannot disagree with what the runtime does. Then fix the markup. Two of these are about the transcript rather than the picture. PAGE_NO_DESCRIPTION and PAGE_CLASS_UNDESCRIBED mean a reader of the transcript loses a step the viewer saw, and data-describe with an empty value is how you say an element is decorative and meant it. PAGE_CLASS_NOT_REDUCED is about reduced motion. No flag duplicates a settings key, so reduced motion is --set motion.reduce=true on any command that runs against the project, and it asks Chromium for prefers-reduced-motion. The page’s own stylesheet is what has to honour that query, and this code says a class it adds still animates when nobody asked it to. PAGE_CLASS_UNDESCRIBED is the other half of data-class. A class change is a change to the picture, so data-describe-class gives each one a description, written as cue and description pairs separated by a vertical bar, and the transcript prints it.

A script that is not ready to be voiced

All three come from decktalk check reading script.md, so all three are free to find and all three are found before a credit is spent. This is the cheapest check there is, and running it in a commit hook with --no-pages costs nothing. Run it before you voice anything. narrate refuses a comment, a brace or a bracket inside a paragraph, and it lists every such line at once. It does not refuse an unfilled blank such as [NUMBER], so a voiced run reads it out. Only check reports that. SCRIPT_SPOKEN_SYMBOL is a warning because sometimes you do mean the symbol. Write out what the voice must say, and Writing for the ear is the guide for it. SCRIPT_PAUSE_DROPPED names a section and a voice whose turns hold a [pause N] on a model that renders no timed pause, once per section and voice, and narrate refuses to buy a take that would lose the pause. Move to a model that renders one, or write a [beat], which every model reads. script.md names the models.

A voice direction that names no voice

Every voice a script hands a turn to needs a [voices.NAME] table, and in a section that names a voice, every turn opens with a [voice NAME] line. A line holding only a note that is exactly a voice’s name, such as [guest], plays as a beat and hands nothing over. All four come from decktalk check reading script.md against decktalk.toml, so decktalk check --no-pages finds them before anything is bought. Write a dialogue shows each.

A take that is missing

A run with --no-spend plays every take on disk and puts a placeholder in each turn whose take is missing, which is one TAKE_MISSING per turn, and one per section when one voice reads it. It is a warning because the film is still whole and only that turn’s timing is estimated, so a draft build exits 0. Pass --fail-on warning to make a missing take fail a run. A take is found by its text, its voice, its model and its voice settings, so a turn reports it after any of those changed, and on a fresh clone whose takes were never committed. Without a voice id no voiced take can be matched at all, and the run says so in one line before the findings. Set [voices.narrator] id in decktalk.toml, which is a published name rather than a secret and is committed with the project, and the takes on disk play again.

A take that plays silence or cuts a word

These three come from narrate, on the run that makes the take, and each names the turn. A take is cut at its sound end, the point after which it stays under narration.sound_end_noise_dbfs for at least narration.sound_end_min_run_seconds. A take with no sound above that level plays its turn as silence, and a word placed after it is never heard. A take whose voice sent no word times is timed by the aligner, and one no aligner timed plays estimated words. Voice one turn again buys a single turn.

When the answer is not a code

Some things are not judgements. Use the stream.
  • --events prints one JSON line per event on stderr as it happens, and every run also appends build/events/<run>.jsonl whether you passed it or not. The event stream names every line and its fields.
  • stage.done and section.done carry an outcome, so a run that stopped early still says what it did not reach rather than leaving you to infer it from a shorter list.
  • events.keep_runs prunes the oldest files, and its default is 20.
  • -v puts debug lines on stderr and prints the traceback of a bug. error[INTERNAL] means a bug in DeckTalk, and -v is what turns it into something worth reporting.
  • error[CANCELLED], exit 130, means the run was stopped, by Ctrl-C or by the caller’s cancel. Every turn voiced before the stop is on disk, so running the command again buys only the rest.
  • decktalk status reports where the project stands and what to run next.
  • Every command, flag and code in one place: CLI
  • Every settings key with its range and its layer: Configuration
  • What a page may declare: The page contract
  • What verify measures and how: Verify
  • The questions before the first build: FAQ