Command line tool (CLI)
The official Shogi Dojo CLI. Post, upload games and script anything you can do in the browser, from a terminal. The same commands work on macOS, Windows and Linux.
1 What you need: Node.js 20 or newer
The CLI itself has no dependencies. All it needs is Node.js — and installing that is the only part that differs by operating system.
With Homebrew:
brew install node
node --version With winget (the official installer works just as well):
winget install OpenJS.NodeJS.LTS
node --version On Debian / Ubuntu — use your own package manager on other distributions:
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs
node --version 2 Install
The command is the same on all three, but on Linux install it into your home directory. A system-wide install needs root, and a CLI is not worth reaching for sudo.
Run:
npm install -g @shogidojo/cli The same command, in PowerShell:
npm install -g @shogidojo/cli Into your home directory, so no sudo is needed. Put the second line in your shell profile (~/.bashrc or ~/.zshrc) as well, so a new terminal still finds it:
npm install -g --prefix ~/.local @shogidojo/cli
export PATH="$HOME/.local/bin:$PATH" Check that it landed:
shogidojo --version
shogidojo --help 3 Sign in
The CLI authenticates with a personal API key. A key can do anything your account can, so treat it as you would your password. An automation can have a named key of its own, read-only if it only reads.
The usual way. A browser opens, you sign in, and the key comes back on its own — it never appears on a command line, so it never reaches your shell history:
shogidojo login --browser On a machine you reached over SSH, --browser alone cannot finish: the key comes back to 127.0.0.1 on the machine that ran the command, so a browser on your own desktop has nowhere to deliver it. Forward a port you pick:
ssh -L 47311:127.0.0.1:47311 you@host
shogidojo login --browser --port 47311 Or paste a key instead. It is read from standard input, so it never reaches your shell history:
shogidojo login --stdin Where there is no browser, such as CI, pass it in the environment instead. Nothing is written to disk:
SHOGIDOJO_TOKEN=rustify… shogidojo whoami For CI, Windmill or any other automation, issue a separate named key; the one on your machine keeps working. The key is shown once (stdout carries the key alone) and is not stored on this machine. With --read-only it can read but not post or change anything:
shogidojo token create --name windmill --read-only --days 90 List the keys you hold (name, scope, created, last used, expiry) and revoke one of them. `app` is the account key, the one the settings page issues:
shogidojo token list
shogidojo token revoke 3 The key is stored in ~/.config/shogidojo/config.json, mode 0600 (%APPDATA%\shogidojo on Windows). To check or remove it:
shogidojo whoami
shogidojo logout 4 Use it
The named commands are shorthand. Everything the app can do is reachable through call.
Publish an article:
shogidojo post create --title "..." --body-file note.md --tag 居飛車 Upload a game record:
shogidojo kif upload game.kif --dir /2026 See which engines you may use, analyse a game, and watch it run:
shogidojo engines
shogidojo analyze game.kif --seconds 5
shogidojo jobs Make a quiz from a game. --ply 44 asks for move 44, showing the position after move 43. --answer may be a move the game did not play (USI, or notation such as △5五歩); the card then keeps the move that was played too:
shogidojo quiz create --game user-1-… --ply 44 --answer △5五歩 --note "Suggested in the post-mortem" --deck Ryuo --public Anything else — --query for a read, omitted for a write:
shogidojo call post.list --query --input '{"page":1}'
shogidojo call quiz.createDeck --input '{"name":"..."}' Everything this server can be asked. The list is exactly what call takes:
shogidojo procedures --grep quiz 5 Writing a post
A post create body is Markdown, with two additions that embed boards and games.
[sfen:<SFEN>] draws a position and [game:<gameId>] embeds a game card. Everything else is plain Markdown:
## After ▲7六歩 △3四歩
[sfen:lnsgkgsnl/1r5b1/pppppp1pp/6p2/9/2P6/PP1PPPPPP/1B5R1/LNSGKGSNL b - 3]
[game:user-1-…] An imported game starts PRIVATE. A [game:] card of it shows for you and is blank for every other reader. Publish it as you import it with --public, or leave it to post create --game, which appends the [game:] token and stops if a PRIVATE game is going into a PUBLIC post (add --publish-game to publish it first):
shogidojo kif import game.kif --public
shogidojo post create --type KIFU --title "..." --body-file note.md --game user-1-… --publish-game To set key positions in an article, take the SFEN after move N and put it in [sfen:] (0 is the start; without --ply, the final position):
shogidojo kif position user-1-… --ply 60 For the same diagram in an article elsewhere, write it out as SVG. --sfen needs no account and no network; --game takes the position, the players and the last move's square from a game. For a PNG, convert the SVG (rsvg-convert, ImageMagick, a browser):
shogidojo diagram --sfen "lnsgkgsnl/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL b - 1" -o start.svg
shogidojo diagram --game user-1-… --ply 60 -o move60.svg
rsvg-convert -o move60.png move60.svg --type is only a label and a feed filter; the body renders the same. ARTICLE is an article, KIFU presents a game record, BOOK presents a book.
post create prints the post's URL, /posts/<id>. A game's page is /review/<gameId> (/game/<id> is the live board), and kif import / upload print it:
Posted #12 https://shogidojo.online/posts/12
Imported game.kif as user-1-…
https://shogidojo.online/review/user-1-… (private — only you can open it) Limits: title 200 characters, body 50,000, up to 20 tags of 40 characters each. The CLI stops before sending anything over them.
6 Procedures for call
--describe tells you what call takes. The server answers with the Zod schema it validates the input against, as JSON Schema, so it cannot drift from the truth. A return shape is shown only for procedures that declare one; the common ones are below (add --query for a read).
See what a procedure takes:
shogidojo procedures --describe quiz.import Game records:
game.importKifFromText {"kifText":"…","dir":"/2026"}
→ {"game_id":"user-1-…"}
game.setGameVisibility {"gameId":"user-1-…","visibility":"PUBLIC"}
→ {"success":true}
game.getFullGameById (read) {"gameId":"user-1-…"}
→ {"game_id":…, "visibility":…, "moves":[{"id":1, "moveNumber":0, "sfen":"…",
"children":[{"childId":2, "usi":"7g7f", "notation":"▲7六歩"}]}, …]}
game.applyMove (read) {"sfen":"…","move":"△5五歩","lastUsi":"7g7f"}
→ {"sfen":"…","usi":"5d5e","notation":"△5五歩","nextSfen":"…"} Posts:
post.create {"type":"KIFU","title":"…","body":"…","tags":["居飛車"],"visibility":"PUBLIC"}
→ {"id":12, …} Quizzes (playedUsi / playedNotation are the move the game played, gameId the source game; both optional):
quiz.import {"title":"…","visibility":"PUBLIC","gameId":"user-1-…",
"items":[{"sfen":"…","answerUsi":"5d5e","answerNotation":"△5五歩",
"nextSfen":"…","note":"…",
"playedUsi":"8a7c","playedNotation":"△7三桂"}]}
→ {"deckId":5,"listIds":[9]}
(or {"deck":{"title":"…"},"lists":[ …the same list… ]} for a named deck) 7 If something goes wrong
Three things account for most of it.
An "Unsupported engine" message or a syntax error usually means Node is too old. 20 or newer is required:
node --version If a global install fails with EACCES, move the install prefix into your home directory rather than reaching for sudo:
npm config set prefix ~/.local
export PATH="$HOME/.local/bin:$PATH" login --browser prints a URL, but the callback inside it points at the loopback address of the machine that printed it. Opening that URL on another machine signs you in there and the key goes nowhere. Over SSH, forward a port and pass it with --port, or paste a key with --stdin — both are above:
shogidojo login --stdin