# Command reference and troubleshooting The `coursebanks` command validates YAML question banks, builds and checks QTI packages, imports supported QTI, and manages optional question rotation records. Run `coursebanks --help` or `coursebanks COMMAND --help` to see the installed command syntax. ## Exit status and output Successful commands return status `0`, print their summary or proposed questions to standard output, and leave standard error empty. Handled input, archive, CSV, and filesystem failures return status `2`, leave standard output empty, and print one `ERROR: ...` diagnostic to standard error without a traceback. Argument parsing errors, such as a missing required option, also return status `2` and print `argparse` usage and an error to standard error. Help returns status `0` and prints usage to standard output. Scripts should use the exit status to decide whether a command succeeded. The text after `ERROR:` is intended to help a person and may include operating-system details that vary by platform. ## Primary conversion commands ### `validate` ```text coursebanks validate SOURCE.yaml ``` This command reads and validates the bank without writing files. On success it prints `Valid: COURSE / BANK_ID: N questions`. ### `build` ```text coursebanks build SOURCE.yaml [--out DIRECTORY] ``` The default output directory is `build`. The command validates the complete bank before creating the directory and writes these four artifacts: - `COURSE_BANK_ID_QTI12.zip`, which is the package uploaded to Canvas. - `instructor_review.md`, which shows question content and answer keys for review. - `question_catalog.csv`, which provides one searchable row per question. - `validation.json`, which records verified item IDs, counts, difficulty totals, and the archive SHA-256 digest. On success it prints `Created ARCHIVE: N questions; SHA-256 DIGEST`. If the output directory already exists, files with these generated names are replaced and unrelated files are preserved. The command has no force option because replacing its named build artifacts is its documented behavior. Validation finishes before any output is created, but a later filesystem failure can leave some generated artifacts from an incomplete build. Remove the incomplete generated files and rerun the command after correcting the destination problem. ### `check-qti` ```text coursebanks check-qti ARCHIVE.zip ``` This command reads the archive without extracting it and writes no files. On success it prints `Valid QTI 1.2 structure: N questions`. Before reading XML, it enforces the documented member-count, uncompressed-size, compression-ratio, and unique-name policy. The check covers this toolkit's supported structure and scoring shape; it does not certify every QTI feature or Canvas rendering. ### `import-qti` ```text coursebanks import-qti ARCHIVE.zip --course COURSE --bank-id BANK_ID --title TITLE --out OUTPUT.yaml [--metadata-csv METADATA.csv] [--force] ``` The command reads and validates the supported QTI subset before writing YAML. On success it prints `Imported N questions into OUTPUT.yaml`. An existing output path is preserved and causes status `2` unless `--force` is supplied. With `--force`, the output YAML is replaced after archive parsing, metadata processing, and bank validation succeed. Parent directories are created as needed, including directory and file names containing spaces. See [Importing QTI into YAML](importing-qti.md) for the compatibility table and metadata CSV format. ## Rotation commands These commands are optional and operate on a validated YAML bank. Assessment names are exact, case-sensitive labels such as `Quiz 1`, `Midterm`, or `Homework 3`. ### `select` ```text coursebanks select SOURCE.yaml --assessment NAME --count COUNT [--history usage.csv] [--seed 0] ``` This command prints a `PROPOSED ONLY` notice followed by selected question summaries. It never creates or changes the history file. ### `record` ```text coursebanks record SOURCE.yaml --term TERM --assessment NAME --ids ID [ID ...] [--history usage.csv] ``` This command validates all supplied IDs and existing history before appending actual usage records. On success it prints `Recorded N actual questions in HISTORY`. A new history file receives a header, while an existing compatible history retains its column order. ### `plan` ```text coursebanks plan SOURCE.yaml --terms TERM [TERM ...] --assessment NAME COUNT [--assessment NAME COUNT ...] --out PLAN.csv [--history usage.csv] [--seed 0] ``` This command computes the complete nonbinding plan before opening its output file and never changes usage history. On success it prints `Wrote proposed, nonbinding rotation of N question uses to PLAN.csv`. An existing plan output is replaced. ## Troubleshooting ### A command reports that a file or directory does not exist Check the path relative to the directory where the command was started, or pass an absolute path. Quote paths containing spaces in a shell, as in `--out "build artifacts"`. ### `import-qti` reports `File is not a zip file` or `Bad CRC-32` The input is not a readable ZIP package or one of its members is corrupted. Obtain a fresh export and pass the ZIP file itself rather than an extracted XML file. ### A QTI archive exceeds a resource limit The diagnostic identifies the member count, individual uncompressed size, total uncompressed size, compression ratio, or duplicate name that was rejected. Inspect the package source rather than weakening a limit for an untrusted file. The exact limits and their scope are listed in the [QTI import guide](importing-qti.md#archive-safety-limits). ### `import-qti` reports that it refuses to overwrite the output Choose a new output path or inspect the existing file and rerun with `--force` when replacement is intended. Without `--force`, the existing bytes are preserved. ### A metadata CSV is rejected The file must be valid UTF-8 CSV with a case-sensitive `ID` header and no rows containing more cells than the header. IDs must match QTI item identifiers exactly. See the [metadata CSV override rules](importing-qti.md#metadata-csv-overrides) for supported columns and values. ### A destination cannot be written Check that every parent component is a directory and that the current user can create or replace files there. No success summary is printed when directory creation or writing fails. For an interrupted or failed build, inspect the output directory and remove incomplete generated artifacts before retrying. ### A valid package is rejected as unsupported QuestionBankToolkit intentionally rejects QTI structures that it cannot convert without loss. Review the [supported item structure](importing-qti.md#supported-item-structure) and the [QTI contract](QTI_specification.md) for the accepted subset.