Quick Start
Requirements
A client machine with Python 3.8 or newer and SSH access, as
root, to the Swarm manager.A cluster: a manager node and GPU worker nodes sharing an NFS export (
/sharedby default). Without one, the local Development Cluster provides the same setup in Docker containers.
Installation
Install the client from PyPI:
pip install graflag
Or from source:
git clone https://github.com/lias-laboratory/graflag.git
cd graflag
pip install -e .
Both install the graflag command.
Configuration
Run the setup wizard:
graflag setup
It asks for the connection details, stores them in
~/.config/graflag/config.env, initialises the Swarm on the manager, joins the
workers listed in hosts.yml and starts the image registry. The file holds:
Key |
Default |
Meaning |
|---|---|---|
|
(required) |
Address of the Swarm manager |
|
|
SSH port on the manager |
|
|
Private key used to reach the manager |
|
|
The NFS export, mounted at the same path on every node |
|
|
Worker IPs; read by |
|
|
NFS port used to mount the export |
|
|
Where method images get |
The wizard asks for the first five; set the last two by editing the file.
graflag setup --reconfigure runs the wizard again.
GraFlag takes its configuration from, in order: the file named by --config;
a .env in the working directory, but only if it defines MANAGER_IP, so
an unrelated project’s .env is never mistaken for one; and
~/.config/graflag/config.env.
Running an Experiment
Build a method’s image and run it on a dataset:
graflag run -m bond_dominant -d bond_inj_cora --build
run checks that the method and the dataset exist, fetches the dataset if
its files are missing, builds and pushes the image (with --build), deploys a
one-shot Swarm service and follows its output until the run ends. Ctrl-C only
detaches from the output: the run continues, and graflag logs -e EXP -f
reattaches. When the run ends, its service is removed, unless --keep-service
is given.
Without --build, the image already in the registry runs, so rebuild after
editing a method. Parameters are overridden without the underscore their
.env declares them with:
graflag run -m taddy -d uci --params MAX_EPOCH=100 LEARNING_RATE=0.001
Every run saves its configuration in its directory on the cluster, as
service_config.json. To replay a run, copy that file to the client and pass
it to run:
graflag copy --from-remote -s experiments/EXP/service_config.json --dest .
graflag run --from-config service_config.json
The method, the dataset, the parameters, the image tag and whether the run had a GPU all come from the file; options given on the command line override them.
Monitoring
graflag status # nodes, services and the shared directory
graflag list experiments # every run and its status
graflag logs -e EXP -f # follow a run's output
graflag stop -e EXP # stop a run; --rm also deletes its directory
Evaluating Results
graflag evaluate -e exp__bond_dominant__bond_inj_cora__20260923_151827
This deploys a short-lived evaluator service. It computes AUC-ROC, AUC-PR,
precision, recall and F1 at k, and the best F1, and writes evaluation.json
and the plots to the experiment’s eval/ directory. Graph Anomaly Detection Result Types
describes what the evaluator expects and which scores it leaves out.
Then check that the number means what it says:
graflag verify -e exp__bond_dominant__bond_inj_cora__20260923_151827
verify compares what the method reported about itself with what it
published – among other checks, that the AUC the evaluator just computed is
the AUC the method printed – and exits 1 when a check fails. See
the CLI reference.
Custom Metrics
Register a custom metric from the Python API:
from graflag import GraFlag
def hits_at_100(scores, ground_truth, **kw):
top = scores.argsort()[-100:]
return {"hits@100": float(ground_truth[top].mean())}
gf = GraFlag()
# Globally: applied to every later evaluation of this result type
gf.register_metric("EDGE_STREAM_ANOMALY_SCORES", hits_at_100)
# Or for one experiment only
gf.register_metric("EDGE_STREAM_ANOMALY_SCORES", hits_at_100,
experiment="exp__taddy__uci__20260309_120000")
register_metric takes the function’s source and writes it as a plugin file
on the cluster, which the evaluator loads before computing metrics. Plugin files
can also be written by hand, in either location:
libs/graflag_evaluator/plugins/– globalexperiments/<exp_name>/custom_metrics/– one experiment
Each plugin registers its function when imported:
# custom_metrics/hits_at_100.py
from graflag_evaluator import MetricCalculator
def hits_at_100(scores, ground_truth, **kw):
top = scores.argsort()[-100:]
return {"hits@100": float(ground_truth[top].mean())}
MetricCalculator.register_metric("EDGE_STREAM_ANOMALY_SCORES", hits_at_100)
Cleaning Up
A run removes its own service when it ends, and graflag stop removes the
service of the run it stops. graflag cleanup removes the ones left behind
otherwise: by a run you detached from with Ctrl-C, or one started with
--keep-service. It touches finished runs only, and keeps a service whenever
the run could not be diagnosed without it:
graflag cleanup --dry-run # what would be removed
graflag cleanup
graflag clear reclaims storage: experiments whose method no longer exists,
datasets used only by them, images no method owns, and stray files at the root
of the share. It only reports unless given --apply:
graflag clear # report what is reclaimable
graflag clear --apply --images # remove images and registry repositories only
graflag clear --apply --gc # also garbage-collect the registry's blobs
Deleting a registry repository frees no disk by itself; --gc does, and stops
the registry while it runs, because collecting blobs from a live registry
corrupts later pushes.
Web Dashboard
graflag gui
Then open http://localhost:5000. The dashboard has no authentication: read
Web Dashboard before running it anywhere but a trusted network.
From an AI Agent
GraFlag also runs as an MCP server, so an agent such as Claude Code can list methods and datasets, launch and watch runs, evaluate and verify them:
pip install "graflag[mcp]" # Python 3.10+
claude mcp add graflag -- graflag mcp
AI Agents (MCP) lists the tools and what they deliberately leave out.