Skip to content

archmage drive

The drive subcommand pulls configuration spreadsheets from Google Drive down to a local directory, so that the regular pipelines — archmage export and archmage struct — can consume them like any other input files.

It has three subcommands: login authorizes Archmage to read your Google Drive, list shows the spreadsheets under a Drive folder, and download pulls them into a local directory.

Everything here is read-only. Archmage never uploads, never writes back to Drive, and never starts an authorization flow outside drive login.

Archmage carries no OAuth client of its own. You create a Desktop app OAuth client in your own Google Cloud project and hand its client ID and client secret to archmage drive login.

The only scope Archmage requests is https://www.googleapis.com/auth/drive.readonly.

Terminal window
archmage drive login [flags]
archmage drive list --root <url> [flags] [<path1> <path2> ...]
archmage drive download --root <url> -o <output-dir> [flags] [<path1> <path2> ...]
Terminal window
# Authorize with your own OAuth client
archmage drive login --client-id=<id> --client-secret=<secret>
# See what is under the folder
archmage drive list --root https://drive.google.com/drive/folders/1AbCdEf
# Pull everything into ./configs
archmage drive download --root https://drive.google.com/drive/folders/1AbCdEf -o ./configs
# Pull one subtree and one wildcard
archmage drive download --root https://drive.google.com/drive/folders/1AbCdEf -o ./configs \
combat "tables/*.xlsx"

Under --root, Archmage recognizes four things:

Item in Drive Result
Folder Traversed; its contents are pulled
Google Sheet Exported as .xlsx
Uploaded .xlsx, .xlsm, .csv Downloaded as-is
Shortcut Resolved to whatever it points at, keeping the shortcut’s own name

A Google Sheet has no extension on Drive, so .xlsx is appended to its name — a sheet named hero lands as hero.xlsx, and a sheet already named hero.xlsx does not get a second extension.

Everything else in the folder — documents, slides, PDFs, images — is ignored, and so is anything in the trash.

Names are checked before anything is downloaded: within a single folder, two items that would land on the same local name, names differing only in case, and names carrying a character that is illegal in a local file name are all reported so you can fix them in Drive.

login runs the authorization once and stores the result on this machine. list and download read it from there.

On a machine with a browser, login prints the authorization URL, opens it, and waits up to 300 seconds for the browser to come back. The URL is printed in full whether or not the browser opens, so you can always paste it yourself.

Archmage assumes the machine has no usable browser when stdout is not a terminal, when SSH_CONNECTION or SSH_TTY is set, or — on platforms other than macOS and Windows — when neither DISPLAY nor WAYLAND_DISPLAY is set. It then switches to the paste flow: run archmage drive login --export on a machine that has a browser, and paste the token it prints into archmage drive login --import on the headless machine.

After a successful authorization, login prints the account it logged in as and the path of the credentials file it wrote.

login takes none of the shared flags.

Force the local browser flow instead of auto-detecting.

OAuth client ID of a Desktop app client in your own Google Cloud project.

Required the first time. Afterwards the pair already stored on this machine is reused, so re-authorizing — switching accounts, granting again — needs no flags at all.

OAuth client secret paired with --client-id. The two are given together; supplying one without the other counts as supplying neither.

Print a token for a headless machine without saving it locally.

The token goes to stdout and everything a human reads goes to stderr, so the token can be piped on its own.

Terminal window
archmage drive login --export --client-id=<id> --client-secret=<secret> 2>/dev/null

Read a token generated by --export from stdin.

The token is read from stdin rather than taken as a flag value, so it stays out of ps output and shell history. The same path serves a human pasting and a piped file.

Terminal window
archmage drive login --import < token.txt

list walks the folder given by --root and prints what it matched, one per line, as paths relative to that folder, in three aligned columns: path, size, and modification time in your own timezone. Folders end with /.

Folders and Google Sheets have no size — Drive reports none for native Docs editor files — so the size column stays blank for them.

list and download take the same path arguments and run them through the same matcher, so a wildcard can be rehearsed with list and then moved over to download verbatim.

Terminal window
archmage drive list --root https://drive.google.com/drive/folders/1AbCdEf
combat/ 2026-08-14 09:41
combat/hero.xlsx 12.4 KB 2026-08-27 17:02
combat/skill.xlsx 8.1 KB 2026-08-26 11:20
item.xlsx 33.7 KB 2026-08-31 20:15

list takes only the shared flags.

download pulls the matched files into --output-dir, preserving each file’s full path relative to --root. Folders holding no downloadable file are not created locally.

One file failing does not stop the rest: failures are collected, reported together at the end, and the command exits non-zero.

Re-download every matched file, ignoring the local cache.

The directory where downloaded files are written. Required.

Delete local files that no longer exist in Drive.

--prune requires a full download — drop the path arguments, or drop --prune. A run narrowed by path arguments never sees the rest of the tree, so everything outside the named subtree would look as though it had vanished from Drive.

Terminal window
archmage drive download --root https://drive.google.com/drive/folders/1AbCdEf -o ./configs --prune

list and download accept path arguments that select part of the tree. A path is relative to --root and slash-separated; a backslash is accepted as a separator too.

  • With no path arguments, the whole tree under --root is matched.
  • Naming a folder matches that folder and everything beneath it.
  • A wildcard — *, ?, [...] — is allowed only in the last segment, and does not cross /.
  • Matching is case-sensitive on every platform.
  • A path argument that matches nothing is an error naming that argument.
Terminal window
# One folder and everything under it
archmage drive download --root <url> -o ./configs combat
# Every spreadsheet directly inside tables/
archmage drive download --root <url> -o ./configs "tables/*.xlsx"

download keeps a cache file named archmage.drive.json in --output-dir, alongside the files it describes, and it is meant to be committed together with them.

The cache records each file’s Drive modification time, so a later run skips the files Drive reports as unchanged and downloads only the rest. --force ignores it.

An output directory whose archmage.drive.json belongs to a different --root folder is rejected: two Drive folders sharing one output directory would overwrite each other’s paths.

These flags are accepted by both list and download.

URL or ID of the Google Drive folder to read. Required.

It takes the folder URL straight from your browser’s address bar. Four forms are accepted:

Form Example
Folder URL https://drive.google.com/drive/folders/1AbCdEf
Folder URL with an account segment https://drive.google.com/drive/u/0/folders/1AbCdEf
open?id= URL https://drive.google.com/open?id=1AbCdEf
Bare folder ID 1AbCdEf

Any query string on the URL is ignored, and a shared drive’s own root folder URL works as well. --root must name a folder; a URL naming a single file is rejected.


Print the Archmage banner on startup.

Number of Drive requests in flight at once (default: 3).

Valid values: 1 to 16.

Change the working directory before running. Relative paths are resolved from this directory.

Load environment variables from the specified file before running. If omitted and a .env file exists in the working directory, it’s loaded automatically.

Maximum Drive requests per second (default: 10).

Valid values: 1 to 100.

Print extra status messages.