Fuzzball Documentation
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

Per-Workflow Charges

Fuzzball tracks resource usage for each workflow it runs and exposes the results through the CLI. Use this view to attribute compute, storage, and egress costs to specific workflows, jobs, and users — orthogonal to the cloud-provider billing covered in Tracking AWS Cloud Spend.

What gets measured

Every workflow accumulates four kinds of charges:

  • Compute — node-hours of the substrate instance(s) running the workflow, priced per provisioner definition.
  • Volume — GiB-hours that any storage volumes remained attached or held data on behalf of the workflow.
  • Egress — bytes leaving the substrate node, bucketed into an egress class and priced per class.
  • Ingress — bytes entering the substrate node. Tracked but not priced today.

Each charge is denominated in credits, the internal accounting unit. Catalog rates are authored against published cloud-provider prices (e.g. AWS EC2 hourly rates, AWS published data-egress rates), so the credit values track those prices directly. There is no automatic conversion to local currency at present.

Viewing per-workflow charges

The fuzzball report charges workflow subcommand prints an itemized table of every charge line tied to one workflow:

$ fuzzball report charges workflow <workflow_id>

CATEGORY | STAGE  | BASIS                    | RATE         | START                 | END                   | QUANTITY           | CREDITS
compute  | worker | t3.small                 | 0.0208       | 2026-06-03 01:29:33PM | 2026-06-03 01:29:37PM | 0.001226 hours     | 0.00002551
egress   | worker | cross_region_aws_service | 0.02         | 2026-06-03 01:29:33PM | 2026-06-03 01:29:37PM | 5285 bytes         | 0.00000010
egress   | worker | via_nat_to_internet      | 0.135        | 2026-06-03 01:29:33PM | 2026-06-03 01:29:37PM | 14015 bytes        | 0.00000176
ingress  | worker |                          | (no pricing) | 2026-06-03 01:29:33PM | 2026-06-03 01:29:37PM | 2044528 bytes      | —
volume   | data   | priced                   | 0.0001       | 2026-06-03 01:29:33PM | 2026-06-03 01:29:37PM | 0.001074 GiB-hours | 0.00000011

The BASIS column shows the rate’s basis: instance type for compute, egress class for egress, storage provisioner name for volume, and blank for ingress (no basis is tracked). Multi-class egress renders one labeled row per class, so each class’s bytes and cost are visible separately rather than aggregated.

Two values in the RATE column are not numeric:

  • (no pricing) — no rate exists in the catalog for that class. Credits show as (cannot be computed). Ingress is always in this state today.
  • (zero rate) — the catalog does have an entry but its rate is 0. Credits compute explicitly to 0.00, distinguishing “intentionally free” (e.g. traffic through an S3 gateway endpoint) from “unpriced.”

CREDITS = RATE × QUANTITY for each row, with unit conversion folded into the rate’s denominator (per hour, per GiB, per GiB-hour, etc.).

Lifetime volume charges

The volume subcommand prints the lifetime accumulated charge on a single storage volume, addressed by volume name, volume ID, or provisioner-name + volume-name:

$ fuzzball report charges volume <volume_name>
$ fuzzball report charges volume <volume_id>
$ fuzzball report charges volume <provisioner_name> <volume_name>

A bare volume name is matched across every provisioner you can see. If the same name exists on more than one provisioner, the command lists the matching provisioner/volume pairs and asks you to qualify the name with the two-argument form.

Useful when a persistent volume has carried multiple workflows and you want the total spend on that volume rather than per-workflow attribution.

The table lists only the workflow attachment windows; the total volume cost below it covers the volume’s full lifetime, including time it was not attached to any workflow.

Workflow charge summaries

For higher-level rollups, fuzzball report charge-summary collapses each workflow’s per-line detail into one summary row per (workflow, category) combination. The workflow subcommand shows the summary for a single workflow; list returns many summaries with filter and pagination options:

$ fuzzball report charge-summary workflow <workflow_id>

$ fuzzball report charge-summary list \
    [--group <group_id>] [--user <user_id>] [--cluster <cluster_id>] \
    [--start-from <RFC3339>] [--start-until <RFC3339>] \
    [--page-size N] [--page-token TOKEN]

The --group flag is repeatable. The --cluster filter only applies on Federate deployments where multiple clusters are aggregated.

The aggregate subcommand collapses everything in the caller’s scope into a single total, with the same filter flags:

$ fuzzball report charge-summary aggregate \
    [--group <group_id>] [--user <user_id>] [--cluster <cluster_id>] \
    [--start-from <RFC3339>] [--start-until <RFC3339>]

--start-from/--start-until bound the aggregate two ways, depending on what the usage is attached to. Compute, egress, and workflow-attached storage are reported for every workflow that started in the period, so a workflow running past --start-until still contributes its whole run to the period it began in. Usage that belongs to no single workflow – persistent volumes and object cache entries – is instead clipped to the period, because those lifetimes span many reports and counting each one in full every time would repeat all prior periods’ usage.

Object cache usage

Objects in the object cache occupy storage from the moment they are cached until they are purged (TTL expiry, disk-pressure eviction, or explicit delete). That usage is metered as GiB-hours against the object’s namespace owner — the group for group/ objects, the user for user/ objects — independent of which workflows read the object.

Object cache usage appears on fuzzball report charge-summary aggregate as its own Object cache line. It is priced by the cluster-wide objectCache rate in central config:

objectCache:
  costPerGbHour: 0.002

The rate is applied at report time, so changing it re-prices all displayed object cache usage, including past periods. With no rate configured, the GiB-hours quantity is still reported but contributes no credits. When a report is bounded with --start-from/--start-until, each object’s cached window is clipped to the requested period.

Scope and visibility

fuzzball report auto-narrows by the caller’s role:

  • Regular users see only their own workflows.
  • Group owners see workflows belonging to groups they own.
  • Organization owners see all workflows in their organization.

The optional --group, --user, and --cluster filters narrow within the caller’s already-permitted scope — they cannot widen it. A regular user filtering by --user for someone else’s workflows will simply see no results.

Egress classes on AWS

When an AWS substrate runs a workflow, each destination address the workload egresses to is classified by walking the source node’s VPC route table. The class determines the rate. Default classes shipped in the AWS egress catalog:

ClassDefault rate (credits/GiB)Triggered when…
intra_az_local0.00Destination is a pod/service in the source node’s own subnet
intra_az_other_subnet0.00Destination is in the source’s AZ but a different VPC subnet
cross_az_intra_vpc0.01Destination is in the same VPC but a different AZ
via_s3_gateway_endpoint0.00Destination resolves to S3 in-region and the VPC has an S3 gateway endpoint
via_dynamodb_gateway_endpoint0.00Same, for DynamoDB
via_privatelink0.01Destination resolves to a configured PrivateLink interface endpoint
cross_region_aws_service0.02Destination is an AWS-published service IP in a region different from the cluster
via_nat_to_internet0.135Default route via NAT gateway (most generic internet egress)
via_igw_to_internet0.09Default route via Internet Gateway (substrate in a public subnet)
unknown0.135Source-instance placement or VPC topology could not be resolved

The unknown class is intentionally priced at the most expensive realistic rate so misclassifications surface as conservative billing rather than free traffic.

On non-AWS deployments (on-prem, Slurm/PBS) the matcher is source-blind: it applies operator-declared CIDR rules from central config instead of walking VPC routing state. The class names emitted in that mode are whatever the operator named in those rules. Rules may use any prefix length, down to a single host (/32), so a specific license server or storage endpoint can carry its own class and rate.

Output format

All fuzzball report subcommands honor the global --output flag:

  • --output table (default) — human-readable.
  • --output json — machine-readable. Useful for piping into downstream spend-attribution tools.

YAML output is not supported for report commands; the data is tabular by nature and YAML adds no value over JSON.