Skip to main content

Nitro AI Judge CLI

PyPI Downloads

naij is a command-line client for judge.nitro-ai.org. It can browse competitions and tasks, download task data, submit solutions, inspect feedback, and launch past competitions locally with Docker.

For a full-screen contest cockpit with searchable contests, ordered tasks, data downloads, local play controls, and submission feedback, run:

naij tui

The TUI can start before login and will prompt for credentials when needed. Selections are shared with the regular naij shell and commands.

3.0 highlights

  • naij tui provides a keyboard-first, full-screen contest cockpit.
  • naij play manager install starts the local Docker-backed Play manager; its dashboard updates live when NAIJ or Docker changes a managed competition.
  • The manager keeps Play services private behind stable Jupyter and submission proxy routes, with operation progress, redacted logs, cancellation, and offline recovery instructions.
  • Disconnect Nitro removes only credentials saved inside the manager. LAN-only Log out expires only the current browser session. Neither action removes CLI credentials or workspaces.

Requirements

  • Python 3.10+
  • Textual 8.2.x (installed automatically)
  • A local Linux-container Docker daemon with the Compose plugin for naij play

Installation

From PyPI:

pipx install nitro-ai-judge-cli

On Arch Linux: available on AUR as nitro-ai-judge-cli

yay -S nitro-ai-judge-cli

From a checkout:

python3 -m pip install .

For local development:

python3 -m pip install -e .

Login

naij login
naij login --username MihneaStoica

Login posts to Nitro's /api/auth/login endpoint and stores the returned access and refresh tokens. Nitro AI Judge refreshes an expired access token when possible and asks you to log in again when the saved refresh token is no longer valid.

Full-screen TUI

Run naij tui for the full-screen interface. Its Yazi-inspired browser keeps contests and one-based tasks in separate columns while the right pane provides four task views:

  1. Overview
  2. Data
  3. Submissions
  4. Play

The layout adapts to the terminal. At 100 columns and wider all three panes remain visible. From 60 through 99 columns, only the active pane is shown and Tab/Shift-Tab cycles contests, tasks, and task details. Below 60 columns or 20 rows, Nitro AI Judge shows a resize message instead of compressing the interface.

The complete keymap is:

  • j/k or Up/Down: move
  • Enter: open
  • h/l or Left/Right: move across browser panes and task views
  • Esc: back
  • Tab/Shift-Tab: cycle panes, or move between form fields
  • /: filter the active contest, task, or submission list
  • r: refresh the active view
  • ?: contextual help
  • q or Ctrl+D: quit
  • 14: select Overview, Data, Submissions, or Play
  • d: open the task-data download form
  • s: open the submission form
  • p: open the Play action menu

Forms use Space to toggle choices and Tab to move; the submission form also has clickable Submit and Cancel buttons, and the Submissions view has a persistent New submission button. That view requests and displays only the signed-in user's submissions. Destructive Play actions require confirmation. Mouse selection, scrolling, tab switching, and field focus are supported as an optional convenience; every workflow remains keyboard-accessible. Hold Shift while dragging when the terminal's normal text selection is needed.

The TUI loads cached contests, tasks, and submissions before connecting. A temporary network failure or expired login leaves that cached content visible with one recovery message at the bottom. When a request detects stale credentials, the TUI refreshes the bearer token and generated site cookie once, retries once, and opens the login form if recovery fails. A real 403 after refresh remains an access-denied error rather than reopening login repeatedly. Loaded task statements are merged into the task cache, so reopening a task can show its full statement before the next network refresh.

Release screenshots and the keyboard walkthrough will be added under docs/assets/ with the v3.0.0 release capture; the recording contract is in docs/assets/README.md.

Help wanted: TUI improvements

Contributions to the TUI are welcome, especially improvements to interaction polish, visual clarity, accessibility, and behavior across terminal sizes. Please open an issue before starting a large redesign, preserve keyboard access and existing CLI behavior, and include a focused Pilot test for behavior changes. See CONTRIBUTING.md before submitting a pull request.

Basic usage

All commands still accept explicit competition and task arguments:

naij contests
naij contests --page 2
naij contests --all-pages
naij tasks algolymp/algolymp-preojia-ix-x
naij task algolymp/algolymp-preojia-ix-x 1
naij download-data algolymp/algolymp-preojia-ix-x 1 -d data
naij submissions algolymp/algolymp-preojia-ix-x 1 -m both
naij submission 3a009d767bd5 --org algolymp --comp algolymp-preojia-ix-x --task-id 1
naij submit algolymp/algolymp-preojia-ix-x 1 -o submission.csv -s solution.py -w

Competitions may be written as either ORG/COMP or ORG COMP. Explicit arguments override saved context for that invocation without changing it.

Persistent context

use saves a competition and optional task for later commands:

naij use                         # show the current context
naij use algolymp/preojia        # select a competition
naij use algolymp/preojia 1      # select a competition and task
naij use 2                       # select a task in the current competition
naij use --clear                 # clear the selection

Changing the competition clears the selected task and submission. Changing the task clears the selected submission.

ls and show follow the current context:

  • With no selection, naij ls lists competitions.
  • With a competition selected, naij ls lists its tasks.
  • With a task selected, naij ls lists its submissions.
  • naij show displays the most specific selected competition, task, or submission.

Commands use saved context when their positional arguments are omitted:

naij tasks
naij task
naij download-data -d data
naij submissions -m both
naij submit -o submission.csv -s solution.py -w
naij submission
naij set-final
naij play

If saved context is missing or stale, Nitro AI Judge reports which naij use command will refresh it.

Downloads and submissions

Download one or more task-file categories with -c/--category. Supported categories are statement, train_data, test_data, sample_output, and custom_archive.

naij download-data -c statement -o TASK.md
naij download-data -c train_data -c test_data -d data
naij download-data -c test_data -o test_data.zip -f

Download options:

  • -c, --category: category to download; repeat for multiple categories
  • -d, --out-dir: destination directory
  • -o, --output: destination file when downloading one category
  • -f, --force: overwrite existing files

Submit options:

  • -o, --output: required submission output file
  • -s, --source: optional source file
  • -n, --note: submission note
  • -w, --wait: wait for judging feedback

Submission-list options:

  • -a, --author: filter by author
  • -p, --page: page number
  • -n, --page-size: results per page
  • -m, --mode: partial, complete, or both

Use naij set-final [SUBMISSION] and naij unset-final [SUBMISSION] to change the final selection. The submission argument may be omitted when one is selected in the interactive shell.

Backend and submission proxy

Use a different API endpoint with either a flag or an environment variable:

naij --api-url http://127.0.0.1:8080 tasks algolymp/preojia
NAIJ_API_BASE_URL=http://127.0.0.1:8080 naij tasks algolymp/preojia

API URL precedence is:

  1. --api-url
  2. NAIJ_API_BASE_URL
  3. the 2.x NITRO_API_BASE_URL fallback
  4. PROXY_URL
  5. https://judge.nitro-ai.org/api

When PROXY_URL supplies the API URL, submission-proxy mode is enabled automatically. It can also be enabled explicitly:

PROXY_URL=http://127.0.0.1:8080 naij submit -o submission.csv -s solution.py
naij --api-url http://127.0.0.1:8080 --submission-proxy submit -o submission.csv -s solution.py
NAIJ_SUBMISSION_PROXY=1 naij submit -o submission.csv -s solution.py

Submission-proxy precedence is --submission-proxy, NAIJ_SUBMISSION_PROXY, the 2.x NITRO_SUBMISSION_PROXY fallback, implicit PROXY_URL mode, then disabled. Empty environment values are ignored; recognized true values are 1, true, yes, and on.

Past-contest play

Version 3 routes every competition operation through one Dockerized Play manager at http://localhost:51123/nitro/. The manager uses the host Docker socket and Compose plugin; it does not run Docker-in-Docker. Competition Jupyter and proxy ports stay private, while their browser routes remain stable under the manager URL.

Install the manager once, then start a competition:

naij play manager install --yes
naij play algolymp/algolymp-preojia-ix-x
naij play status algolymp/algolymp-preojia-ix-x
naij play cancel algolymp/algolymp-preojia-ix-x
naij play logs algolymp/algolymp-preojia-ix-x
naij play logs -f algolymp/algolymp-preojia-ix-x
naij play stop algolymp/algolymp-preojia-ix-x
naij play start algolymp/algolymp-preojia-ix-x
naij play restart algolymp/algolymp-preojia-ix-x
naij play recreate algolymp/algolymp-preojia-ix-x
naij play delete-container algolymp/algolymp-preojia-ix-x
naij play delete-image algolymp/algolymp-preojia-ix-x
naij play delete-workspace algolymp/algolymp-preojia-ix-x --force

The competition can be omitted when saved context supplies it. naij play ORG/COMP means play play ORG/COMP; the old up and down spellings remain parseable as migration aliases.

Lifecycle behavior:

  • play, pull, start, stop, restart, and recreate are idempotent, asynchronous manager operations. Identical concurrent requests share one operation; conflicting requests report competition_busy.
  • Explicit stop remains stopped until the user starts or recreates it.
  • delete-container removes containers and the private project network but preserves /home/jovyan.
  • delete-image removes only that competition's cached image tags after its containers are deleted; workspace data is preserved.
  • delete-workspace requires the full organization/competition reference in interactive use. Automation must pass --force.
  • logs is redacted before it leaves the manager; logs --follow streams it.
  • cancel requests cancellation of the latest queued or running operation.
  • --gpu requires GPU access, --no-gpu disables it, and the default probes automatically. --pull always|missing|never retains Compose-style policy.
  • --open opens Jupyter after a successful play or recreate; commands do not open a browser by default.

The retired competition --port, --proxy-port, and --bind flags produce guidance instead of publishing a container port. Configure the single manager endpoint with naij play manager install --bind ... --port ....

Manager lifecycle commands are:

naij play manager status
naij play manager update --yes
naij play manager open
naij play manager stop
naij play manager start
naij play manager restart
naij play manager sync-credentials
naij play manager uninstall

Uninstall removes the manager container and network but preserves its private SQLite volume, configuration, competition metadata, images, and every workspace. manager purge --force removes only manager-private SQLite state; it never removes competition workspaces.

LAN access and TLS

Loopback is the safe default. A non-loopback bind is rejected unless all three of --tls-cert, --tls-key, and an HTTPS --public-url are supplied. LAN mode uses a separate dashboard login token at ~/.naij/play-manager/dashboard-login-token, rate-limits login, and still requires the private CLI API credential for CLI calls:

naij play manager install --yes \
  --bind 0.0.0.0 --port 51123 \
  --tls-cert /absolute/path/cert.pem \
  --tls-key /absolute/path/key.pem \
  --public-url https://play.example.test:51123

The dashboard uses strict Host and Origin validation, SameSite sessions, CSRF, CSP, and clickjacking protection. Access and refresh tokens are synchronized through the authenticated API after install, login, or refresh and never appear in URLs, Compose values, logs, or dashboard HTML.

Migration and recovery

Installation examines only known 2.x generated state and exact Compose labels, then sends a sanitized adoption manifest. The first action lazily cuts over a verified legacy environment. An unlabeled named workspace is reused without alteration; a container-layer workspace is copied into a labeled volume while the stopped legacy container remains recovery evidence until the new routes pass validation. Failed cutover removes only newly manager-labeled objects and restarts the old container.

An update retains the previous image and generated configuration. If the new manager does not become healthy, the CLI restores and restarts the previous configuration. See the architecture document for the runtime model, labels, API, and recovery boundaries.

Interactive shell

Run naij without a command to start the shell. Its contest, task, and submission selection persists between sessions.

$ naij
Nitro AI Judge Interactive Shell. Type `help` for commands.
[naij] > ls
[naij] > 2
[naij algolymp/preojia] > ls
[naij algolymp/preojia] > use 1
[naij algolymp/preojia 1] > show
[naij algolymp/preojia 1] > submit -o submission.csv -s solution.py -w
[naij algolymp/preojia 1] > ..
[naij algolymp/preojia] > q

Shell conveniences:

  • cd is a shell-only alias for use; cd .., .., back, and unselect move up one selection level.
  • pwd prints the full current selection, l aliases ls, and h or ? aliases help (including h COMMAND).
  • ls, use, and show retain the same context-sensitive behavior as direct commands. Shell aliases are not top-level naij commands.
  • A completed contest, task, or submission selects it directly; bare numbers remain available for indexed navigation.
  • help COMMAND displays command-specific help.
  • All regular commands work without a leading naij.
  • Tab completes the current word; press it twice to list ambiguous matches. GNU Readline also supports forward/backward cycling with Tab/Shift-Tab.
  • Completion is case-insensitive and slash-aware, and covers commands, options, enum values, competitions/tasks/submissions, and filesystem paths.
  • Up/Down and Ctrl-P/Ctrl-N navigate history, Ctrl-R searches history, and Ctrl-L clears the screen. Home/End, Ctrl-A/Ctrl-E, Ctrl-Left/Ctrl-Right, Ctrl-W, Ctrl-U, and Ctrl-K provide standard line editing in GNU Readline and libedit.
  • Ctrl-C cancels the current line, Ctrl-D exits, and invalid input returns to the prompt.

Native completion

Generate completion for zsh, bash, or fish:

naij completion zsh
naij completion bash
naij completion fish

For the current shell session:

# zsh, after compinit
source <(naij completion zsh)

# bash
source <(naij completion bash)

# fish
naij completion fish | source

Completion resolves the current argument slot and shows only its next useful level. It does not mix options with an available contest, task, or submission; typing - switches immediately to remaining valid options. It lazily fetches a missing entity list on the first relevant Tab and saves it in the context cache. It fetches all competitions, only the selected or supplied competition's tasks, or the current user's partial and complete submissions for the selected task. Existing cache entries, including empty lists, suppress later requests; authentication and network failures stay silent and can be retried on a later Tab. Bare native completion remains command-only, while a blank interactive prompt offers only entities at the current context level.

State and security

By default, Nitro AI Judge stores credentials, context, shell history, and play data under ~/.naij/:

~/.naij/state.json
~/.naij/context.json
~/.naij/history
~/.naij/play-manager/manager.json
~/.naij/play-manager/compose.json
~/.naij/play-manager/cli-api-token
~/.naij/contestant-cloud/        # read-only 2.x migration source

Override the root with:

NAIJ_STATE_DIR=/some/path naij login
naij --state-dir /some/path login

State-directory precedence is --state-dir, NAIJ_STATE_DIR, the 2.x NITRO_STATE_DIR fallback, then ~/.naij.

The state directory is mode 0700; credential, context, and history files are mode 0600. Writes use a same-directory temporary file, fsync, and atomic replacement. Corrupt credentials are left untouched and produce a recovery-oriented login error. Corrupt context is ignored with a warning.

Command compatibility

naij remains canonical. The deprecated nitro-cli executable delegates to the same entry point and now remains available until 4.0.0. There is no legacy Python import package.

The legacy NITRO_STATE_DIR, NITRO_API_BASE_URL, and NITRO_SUBMISSION_PROXY variables remain lower-priority compatibility fallbacks for the 3.x transition.

Default state moves from ~/.nitro-cli to ~/.naij. If only the old directory exists, Nitro AI Judge renames it before loading state. If both exist, Nitro AI Judge uses the new directory, leaves the old one untouched, and warns once per process. If the rename fails, Nitro AI Judge uses the old directory for that run and prints manual-migration guidance. Setting either state-directory environment variable disables automatic default-path migration.

Generated native completion registers both command names while invoking naij internally.

Publishing

The release workflow runs host tests on Linux, Windows, and macOS, builds and checks the CLI, builds the manager, and runs Linux Docker integration. A release tag must exactly match pyproject.toml. It refuses an existing immutable GHCR tag, publishes linux/amd64 and linux/arm64, then updates the matching 3.0 and stable tags. PyPI publication happens only after GHCR succeeds. The development branch publishes edge; neither the workflow nor installer uses latest.

Recommended release checks:

python3 -m unittest discover -s tests -v
python3 -m pip install --upgrade build twine
python3 -m build
python3 -m twine check dist/*
docker build -f manager/Dockerfile -t naij-play-manager:dev .
NAIJ_DOCKER_INTEGRATION=1 NAIJ_PLAY_MANAGER_IMAGE=naij-play-manager:dev \
  python3 -m unittest discover -s tests/integration -v
git tag v3.0.2
git push origin main --tags

PyPI project: nitro-ai-judge-cli

PyPI does not allow re-uploading an existing filename, and GHCR exact version tags are treated as immutable. A new release requires a new version and matching tag. Trusted publishing targets this repository and the pypi environment.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nitro_ai_judge_cli-3.0.2.tar.gz (1.3 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nitro_ai_judge_cli-3.0.2-py3-none-any.whl (1.3 MB view details)

Uploaded Python 3

File details

Details for the file nitro_ai_judge_cli-3.0.2.tar.gz.

File metadata

  • Download URL: nitro_ai_judge_cli-3.0.2.tar.gz
  • Upload date:
  • Size: 1.3 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for nitro_ai_judge_cli-3.0.2.tar.gz
Algorithm Hash digest
SHA256 a0114863b60e5d34994564a8e2232d823c260dad1b1fa54ce4211338027dc701
MD5 41d8aa9f2af2c94f82432e41a582900d
BLAKE2b-256 397494781081a199b83641192693eeb90708cc5a02e8e6110251009cb96b3845

See more details on using hashes here.

Provenance

The following attestation bundles were made for nitro_ai_judge_cli-3.0.2.tar.gz:

Publisher: publish.yml on MihneaTeodorStoica/nitro-ai-judge-cli

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file nitro_ai_judge_cli-3.0.2-py3-none-any.whl.

File metadata

File hashes

Hashes for nitro_ai_judge_cli-3.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 30770c5567ee40ee80977cf5490708784f6ad72d83f06b493e34da907bee9a21
MD5 6262680ea8415645fe4cbc0c59620fee
BLAKE2b-256 ecf8521e64fe7e634da4e7b79479bc9ca77b078314aa302051c11aa3c669eda8

See more details on using hashes here.

Provenance

The following attestation bundles were made for nitro_ai_judge_cli-3.0.2-py3-none-any.whl:

Publisher: publish.yml on MihneaTeodorStoica/nitro-ai-judge-cli

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

3.1.4

2 files

3.1.3

2 files

3.1.0

2 files

3.0.4

2 files

3.0.3

2 files

This release

3.0.2 This release

2 files

3.0.1

2 files

3.0.0

2 files

2.2.1

2 files

2.2.0

2 files

2.1.1

2 files

2.1.0

2 files

2.0.0

2 files

1.8.2

2 files

1.8.1

2 files

1.8.0

2 files

1.7.1

2 files

1.6.0

2 files

1.5.0

2 files

1.4.0

2 files

1.3.1

2 files

1.3.0

2 files

1.2.0

2 files

1.1.1

2 files

1.1.0

2 files

1.0.0

2 files

0.2.0

2 files

0.1.4

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page