docs / environments-sdk / getting startedgithub.com/Fareground/environments-sdk ↗

Build your first environment

Run a retailer for four weeks. Each week, the retailer orders stock, customers buy what is available, and the engine records cash and inventory. This example requires no API key.

1. Install

Install environments-sdk from PyPI:

python -m pip install --upgrade fg-env

Use Python 3.11 or later. These examples target fg-env 0.7.1; pin that version when you need a reproducible deployment. Save the following contract as inventory.json:

{
  "name": "Weekly inventory decision",
  "brief": {
    "situation": "A retailer serves weekly demand from one stock pool.",
    "rules": "Choose a replenishment quantity before demand arrives. Orders arrive immediately in this introductory model."
  },
  "clock": {
    "rounds": 4,
    "unit": "week"
  },
  "inputs": {
    "weekly_demand": {
      "type": "int",
      "default": 6,
      "min": 0
    },
    "unit_price": {
      "type": "number",
      "default": 10,
      "min": 0
    },
    "unit_cost": {
      "type": "number",
      "default": 4,
      "min": 0
    }
  },
  "types": {
    "retailer": {
      "agent": true,
      "props": {
        "stock": 10,
        "cash": 100.0,
        "sold": 0,
        "lost": 0
      }
    }
  },
  "entities": {
    "shop": {
      "type": "retailer",
      "name": "Shop"
    }
  },
  "actions": {
    "replenish": {
      "by": "retailer",
      "description": "Purchase inventory before this week\u2019s demand.",
      "params": {
        "qty": {
          "type": "int",
          "min": 0,
          "max": 20
        }
      },
      "when": {
        "expr": "$actor.cash >= $params.qty * $inputs.unit_cost",
        "why": "The order exceeds available cash."
      },
      "do": [
        "$actor.cash -= $params.qty * $inputs.unit_cost",
        "$actor.stock += $params.qty"
      ]
    }
  },
  "events": [
    {
      "phase": "end",
      "each": "retailer",
      "do": [
        "$units = $min($it.stock, $inputs.weekly_demand)",
        "$it.stock -= $units",
        "$it.sold += $units",
        "$it.lost += $inputs.weekly_demand - $units",
        "$it.cash += $units * $inputs.unit_price"
      ]
    }
  ],
  "views": {
    "position": {
      "for": "retailer",
      "show": "Stock: {stock}. Cash: {cash|money}. Demand each week: {$inputs.weekly_demand}."
    }
  },
  "invariants": [
    "$entity(shop).stock >= 0",
    "$entity(shop).cash >= 0"
  ],
  "metrics": {
    "stock": "$entity(shop).stock",
    "cash": "$entity(shop).cash"
  },
  "outputs": {
    "units_sold": "$entity(shop).sold",
    "lost_sales": "$entity(shop).lost",
    "closing_cash": "$entity(shop).cash"
  },
  "policies": {
    "steady": {
      "rules": [
        {
          "do": "replenish",
          "with": {
            "qty": 6
          }
        }
      ]
    }
  },
  "arms": {
    "baseline": {},
    "busy": {
      "inputs": {
        "weekly_demand": 9
      }
    }
  }
}

2. Check and preview

fg-env check inventory.json
fg-env preview inventory.json shop

check validates the contract and plays a smoke round. preview shows the retailer's brief, current information, and available tools. A successful smoke check is an authoring aid; it does not establish the model's business accuracy.

3. Run a repeatable policy

Save this as run_inventory.py beside the contract:

import fg_env

result = fg_env.run("inventory.json", {"retailer": "policy:steady"}, seed=7)
print(result.outputs)
assert result.outputs == {"units_sold": 24, "lost_sales": 0, "closing_cash": 244.0}
python run_inventory.py
fg-env run inventory.json --seed 7 --agent retailer=policy:steady --json

The policy orders six units each week. Opening stock is 10, purchases total 24, and sales total 24. Closing stock stays 10. Closing cash is 100 - 24 × 4 + 24 × 10 = 244.

4. Change the scenario

result = fg_env.run(
    "inventory.json",
    {"retailer": "policy:steady"},
    inputs={"weekly_demand": 9},
    seed=7,
)
print(result.outputs)
assert result.outputs["lost_sales"] == 2

The same policy now sells 34 units and loses two sales over four weeks. This is a useful known-answer test: demand increased while supply stayed fixed.

Assumptions in this example

There is one product, fixed demand, immediate replenishment, no storage cost, and no credit. closing_cash is cash, not accounting profit. Real use cases may need delivery delays, multiple products, returns, price responses, or capacity constraints. Add those only when the scenario needs them; see business modeling.

Next steps

Translate your brief into a contract, connect a participant, or explore complete examples.