Forge CLI
The Forge CLI (forge) is a Python command-line tool to work with and operate
Forge services. It authenticates you against
Forge ID and talks to the Forge APIs for you, so you
can script things that would otherwise require clicking through
Operator or hand-crafting curl calls.
It is the replacement for Poulpy, which is now deprecated and unmaintained. If you are coming from Poulpy, read Migrating from Poulpy.
Commands and options may change between versions. The output of
forge <command> --help is always the source of truth: if this documentation
and the CLI disagree, the CLI is right (and you can
tell us about it).
What you can do with it
- Get a JWT to call Forge APIs manually or from your own scripts.
- List the activities, groups and submissions you manage.
- Download student traces in bulk, for one assignment or for one group.
- Generate CSV reports about validation and success rates.
- Rerun moulinettes on a whole submission.
- Clone every student repository of an activity at once.
- Generate a skeleton to bootstrap a new activity.
The Forge CLI does not validate or deploy activity.yml and tenant.yml
files. Deployment is handled by the GitLab CI pipeline of your activity
repository, see Deploy Projects.
Installation
The source code is hosted on the Forge GitLab. Start by cloning it:
git clone https://gitlab.cri.epita.fr/forge/tools/cli.git forge-cli
cd forge-cli
With uv (recommended)
The Forge CLI is packaged with the uv Python package manager. Install uv by following the official instructions, then install the dependencies of the project:
uv sync
You can now run the CLI from the repository:
uv run forge --help
If you would rather have a forge command available everywhere instead of
having to cd into the clone, install it as a uv tool:
uv tool install .
forge --version
PATHIf your shell cannot find forge after uv tool install, run
uv tool update-shell and open a new shell.
With Nix
A flake is provided, so you can run the CLI without installing anything:
nix run .# -- --help
A development shell with Python and uv is also available with nix develop.
With Docker
An image is published on the Forge registry. The entrypoint of the image is
forge itself, so you only pass arguments to it:
docker run --rm -it \
-p 2097:2097 \
-v "$HOME/.config/forge-cli-credentials.json:/forge/.forge-cli-credentials.json" \
-v "$PWD:/forge/data" \
registry.cri.epita.fr/forge/tools/cli:latest --help
The -p 2097:2097 option is required for
authentication to work, as the image is configured to listen
for the OIDC callback on all interfaces. The container works in /forge, so
mount the directory in which you want your downloads to land (here $PWD into
/forge/data).
Docker creates a directory when you bind-mount a file that does not exist
yet. Run touch "$HOME/.config/forge-cli-credentials.json" before the first
docker run.
Updating
The CLI is not auto-updated: pull the repository and sync the dependencies again.
git pull
uv sync
If you installed it as a uv tool, reinstall it after pulling:
uv tool install --reinstall .
Check which version you are running with:
forge --version
Authentication
Every command that talks to a Forge service authenticates you through
Forge ID with an OIDC authorization code flow. The
first time you run such a command, the CLI starts a local HTTP server on
http://localhost:2097/complete/epita/ and prints a URL to visit:
$ forge auth token
You need to log in
Please visit this URL : https://cri.epita.fr/authorize?client_id=...
Open that URL in your browser, log in, and the CLI resumes on its own once the
CRI redirects you back to localhost. Credentials (an ID token and a refresh
token) are then written to disk, and subsequent runs refresh the token silently
without asking anything.
Getting a JWT
forge auth token prints the JWT on stdout, which makes it easy to inject in
your own requests:
curl --fail -H "Authorization: Bearer $(forge auth token)" \
https://operator.forge.epita.fr/api/activities
$(forge auth token)Unlike Poulpy, the login instructions are printed on stdout too. If your
credentials are missing or expired, they end up captured by the command
substitution instead of being shown to you. Always run forge auth token once
on its own after installing, and whenever a script starts failing for no
apparent reason.
To put the token directly in your clipboard on Linux:
forge auth token | wl-copyfor Wayland (requireswl-clipboard)forge auth token | xsel -bfor X11
JWTs are sensitive credentials that should not be shared with anyone, and neither should the credentials file described below.
Authenticating from a remote machine
The OIDC callback goes to localhost:2097 on the machine running your
browser. If you run the CLI over SSH, forward the port before logging in:
ssh -L 2097:localhost:2097 user@remote
The listening address can be changed with the FORGE_OIDC_BIND_ADDR
environment variable (the port is always 2097).
Configuration
Credentials file
Tokens are stored in ~/.config/forge-cli-credentials.json. It is a plain JSON
file, so you can read the current token with jq if you need to:
jq -r .id_token ~/.config/forge-cli-credentials.json
Note that CRI tokens are short-lived: prefer forge auth token, which refreshes
the token for you, over reading the file directly. Deleting this file is the
supported way to log out or to recover from a corrupted state.
Environment variables
| Variable | Default | Description |
|---|---|---|
FORGE_CREDENTIALS_PATH | ~/.config/forge-cli-credentials.json | Where tokens are stored |
FORGE_OIDC_BIND_ADDR | 127.0.0.1 | Address the OIDC callback server listens on |
URIs
Most commands take a URI rather than a name. URIs are slash-separated paths built from the slugs of your tenant and of your activity configuration:
| Kind | Shape | Example |
|---|---|---|
| Activity URI | <tenant>/<activity> | epita-ing-assistants-acu/42sh |
| Assignment URI | <tenant>/<activity>/<assignment> | epita-ing-assistants-acu/42sh/step-1 |
| Submission definition URI | <tenant>/<activity>/<assignment>/<submission> | epita-ing-assistants-acu/42sh/step-1/final |
You can list the URIs you have access to with
forge activities list and
forge activities submissions list.
Troubleshooting
Cannot get ... / HTTP 403
You are authenticated, but you do not have the permissions required on that tenant or activity. Ask a manager of the tenant to grant them to you.
MaxRetriesExceeded
The CLI retried a call twice after re-authenticating and still got a 401.
Delete ~/.config/forge-cli-credentials.json and log in again with
forge auth token.
The command hangs after the browser redirect
Something else is already listening on port 2097, or the port is not
reachable from your browser (remote machine, container). See
Authenticating from a remote machine.