A reusable, multi-agent system that assesses oil & gas fields — primarily on the Norwegian Continental Shelf (NCS) — and produces a grounded recommendation on whether to rejuvenate, develop, or explore them. It pairs specialist agent skills (markdown) with a field-agnostic Python engine that loads any field's data, runs subsurface analytics, applies a transparent 4-gate decision framework, and writes the recommendation with a full uncertainty spread and an independent assurance (red-team) review.
Built and validated on the Volve public dataset (Equinor); ships with a synthetic field so it runs end-to-end on a fresh clone with no data download.
Give it a field (production history + optionally a simulation model + reports) and it returns:
- Updated recovery assessment — OOIP, recovery factor, remaining oil in place, EUR, decline, waterflood diagnostics.
- Ranked pathways with uncertainty — bypassed/attic oil, infill, waterflood optimization, EOR, well interventions — each with P90/P50/P10 volumes, EMV, breakeven price, and flip threshold.
- A recommendation via a 4-gate framework (Volume → Access → Economics → Risked), with an explicit confidence level.
- An assurance (red-team) review — an independent agent attacks the case before the verdict finalizes, flagging load-bearing assumptions, single points of failure, and the price/volume at which the recommendation reverses.
# Volve — SMARTS Assessment (rejuvenation mode)
*Sodir resource class context: RC3–RC5 (contingent + possible resources)*
## Recommendation: REJUVENATE (CONDITIONAL) (confidence: medium)
| Gate | Question | Result | Evidence |
| G1 Volume | material recoverable volume? | ✅ PASS | remaining OIP 11,986,597 sm3, P50 prize 6,472,762 sm3 |
| G2 Access | physically reactivatable? | ⚠️ CONDITIONAL | decommissioned; host likely removed; wells likely P&A'd |
| G3 Economics | a pathway NPV-positive? | ✅ PASS | best=waterflood_optimization, EMV $38M, breakeven $23/bbl |
| G4 Risked | risked EMV > do-nothing? | ✅ PASS | risked EMV $88M |
### Sensitivity & uncertainty
- Price flip threshold: weakest pathway turns negative below $23/bbl (margin $47).
- Leading pathway NPV spread: P90 $36M | P50 $60M | P10 $84M (EMV $38M).
### Assurance review — grade: medium
- Single point of failure: bypassed-oil volumes rest on field-level FOIP (no region breakdown).
- To raise assurance: re-run sim with ROPR/RWPR to locate bypassed oil.flowchart TD
FP[Field pack<br/>fields/<name>/field.yml] --> LOAD[field_loader<br/>validate + load]
LOAD --> DQ[(data-quality-agent<br/>grade A–D)]
DQ --> ENGINE{analysis_engine<br/>recovery • decline • waterflood}
ENGINE --> AGENTS[Specialist agents]
AGENTS --> RES[reservoir]
AGENTS --> GEO[geoscience]
AGENTS --> PROD[production]
AGENTS --> FAC[facilities]
AGENTS --> ECON[economics]
AGENTS --> NCS[ncs-context]
RES & GEO & PROD & FAC & ECON & NCS --> ASSUR[(assurance-agent<br/>red-team)]
ASSUR --> GATES[4-gate framework]
GATES --> G1[G1 Volume]
G1 --> G2[G2 Access]
G2 --> G3[G3 Economics]
G3 --> G4[G4 Risked]
G4 --> REC[Recommendation<br/>+ uncertainty + risk register]
REC --> OUT[assessment.md / --json]
The developer agents build the case; the assurance agent breaks it; the integration logic weighs both into the final verdict. This two-team (develop / challenge) pattern mirrors an independent peer assist at a decision gate.
A rejuvenation/development/explore decision is a cascade of gates. Fail an early gate and later ones are moot.
| Gate | Question asked | Pass criterion | "Conditional" means |
|---|---|---|---|
| G1 Volume | Is there material recoverable volume? | remaining OIP > 0.5 MM sm³ or P50 rejuvenation prize > 0.5 MM sm³ | volume present but basis is analytical-only (no OOIP) → lower confidence |
| G2 Access | Can it physically be reactivated? | field is producing/shut-in with active infrastructure | field decommissioned → host/wells status must be surveyed before capital |
| G3 Economics | Is at least one pathway value-positive? | ≥1 pathway with NPV > 0 at base price and EMV > 0 | only marginal pathways positive → recommendation hinges on price |
| G4 Risked | Does risked EMV beat do-nothing? | best pathway EMV (+ decom deferral credit) > 0 | EMV barely positive → price-sensitive, flag in risk register |
A hard fail at any gate drives the verdict. The recommendation verb changes with --mode: rejuvenate / develop / explore.
Every agent emits a structured Finding block — the only coupling between agents. This is what makes each agent independently testable and replaceable:
### Finding: reservoir-engineering-agent
Confidence: high
Key numbers:
OOIP: 21967456 sm3 # (method: simulation)
RF_to_date: 45.4 %
remaining_OIP: 11986597 sm3
drive_mechanism: waterflood
waterflood_VRR: 0.93
EUR_business_as_usual: 10972353 sm3
Opportunities: # ranked, each with P90/P50/P10 + capex class
- {mechanism: bypassed_attic_oil, P90: 1438392, P50: 2996649, P10: 3955577, capex_class: high}
Blockers:
- region-level OIP not in summary vector — needs model re-run
Hand-off: geoscience-model-agentThe same structure is emitted as JSON via --json (see CLI & machine-readability).
# 1. Clone & install (Python 3.10+)
git clone https://github.com/ojaogezi/Subsurface-Agent.git
cd Subsurface-Agent
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e .
# 2. Assess the in-repo synthetic field (needs no data download)
smarts-assess fields/nordkapp_beta
# equivalent: python -m smarts.assess fields/nordkapp_beta
# 3. (Optional) fetch the real Volve data, then assess it
python scripts/get_volve_data.py # check / instructions
smarts-assess fields/volveOutput is written to fields/<name>/assessment/<name>-assessment.md.
from smarts import load_field, assess_recovery, decline_analysis
field = load_field("fields/volve")
rec = assess_recovery(field)
print(f"OOIP {rec.ooip_sm3:,.0f} sm3, RF {rec.rf_to_date_pct:.1f}%")smarts-assess fields/<name> [options]
--mode {rejuvenation,development,exploration} # scope of the recommendation
--price 65 # override oil price (USD/bbl)
--discount-rate 0.08 # override real discount rate
--decom-liability-usd 500000000 # for decom-deferral credit
--json # emit structured JSON to stdout--json emits the full dossier (gates, technical picture, pathways with P90/P50/P10, economics with EMV + flip thresholds, data-quality grade, assurance review) — so SMARTS can be used as a tool by other agents or pipelines. The structured output is the natural basis for an MCP server (see Roadmap).
SMARTS spans three use cases, mapped to the Sodir (former NPD) resource classification so outputs resonate with an NCS audience:
| Mode | Use case | Sodir RC context |
|---|---|---|
rejuvenation |
late-life / brownfield / decommissioned field | RC3–RC5 (contingent + possible resources in a discovered field) |
development |
a discovered accumulation pending development | RC2–RC3 (contingent resources) |
exploration |
a prospect (no production history) | RC6–RC7 (prospective resources — GRV/CoS based) |
Honest scope note: the engine is fully built out for rejuvenation/development (production history + simulation results). The
explorationmode is framed and the decision logic applies, but volumetric-from-GRV and chance-of-success tooling is on the roadmap — see below.
Each agent is an independently-usable skill in agents/. The orchestrator (skills/SKILL.md) routes a field question through them.
| Agent | Role |
|---|---|
| data-quality | grades input completeness/quality (A–D) before specialists run |
| reservoir-engineering | OOIP, RF, material balance, PVT, decline, waterflood |
| production-wells | per-well decline, water cut, interventions |
| geoscience-model | static model, faults, contacts, bypassed-oil targets |
| facilities-integrity | facilities, integrity, reactivation feasibility |
| economics-commercial | capex/opex, NPV/EMV, price thresholds |
| ncs-context | NCS fiscal regime, infrastructure, regulatory, analogs |
| assurance | independent red-team — attacks the case before the verdict |
| integration-decision | 4-gate framework, final recommendation + risk register |
smarts/ Importable Python package (the engine)
field_loader.py Load + validate a field pack (data contract)
analysis_engine.py Analytics: recovery, decline, waterflood,
opportunities, economics, data-quality, assurance
assess.py Orchestrator → assessment + recommendation + JSON
config/
field_data_contract.md The data contract any field must conform to
field.yml.template Copy this to add a new field
fields/
volve/ Volve pack (config only; data via scripts/)
nordkapp_beta/ Synthetic field — ships in-repo, proves reusability
agents/ + skills/SKILL.md 9 specialist agent skills + orchestrator
tests/ Reusability regression (pytest + standalone)
.github/workflows/tests.yml CI: runs the synthetic regression on push
scripts/get_volve_data.py Fetch/verify the public Volve dataset
ncs_reference/ NCS fiscal/regulatory/infrastructure reference
⚠️ Data governance: the real Volve dataset is ~1.8 GB (Eclipse binaries) and is not committed. If you add proprietary/licensed field data, never commit it —.gitignoreexcludesfields/*/data/andfields/*/assessment/, so put licensed production/model data underfields/<name>/data/(and pointfield.ymlthere), not directly in the pack root. Keep onlyfield.yml(configs) in git. The in-reponordkapp_betadata is synthetic and safe to ship.
mkdir fields/<your_field>and copyconfig/field.yml.template→field.yml.- Fill in identity, lifecycle, and column mapping (so your production file's columns map to the contract).
- Add data under
fields/<name>/(or pointfield.ymlpaths at shared data). - Run
smarts-assess fields/<your_field>.
The system is tolerant of partial data: no simulation model → analytical-only mode; no per-region vectors → flags the gap; missing PVT → uses correlations. Missing data degrades the data-quality grade and confidence, never crashes.
pip install -e ".[dev]"
pytestCI runs the synthetic nordkapp_beta regression on every push (Python 3.10–3.12). The Volve test is a validation claim: when the ~1.8 GB data is present, it asserts cumulative oil matches the published figure (~63 MMbbl, tolerance ±3) and that history ↔ simulation agree to <2%. It auto-skips on a fresh clone.
| Field | Region | Drive | Status | Result |
|---|---|---|---|---|
| Volve (real) | North Sea | waterflood | decommissioned | REJUVENATE (CONDITIONAL) — gated on facilities |
| Nordkapp Beta (synthetic) | Norwegian Sea | gas-injection | producing | REJUVENATE — late-life optimization |
- Exploration mode tooling — GRV/N:G/φ/Sw volumetrics with Monte-Carlo, geological chance of success, EMV-based drilling decisions (RC6–RC7).
- Tornado / parameter sweeps — full sensitivity output per pathway (currently a one-line summary).
- MCP server — expose SMARTS as a tool other agents can call (the
--jsonoutput is the basis). - OPM/interSECT runner — execute open-source simulation (not just read existing results).
- SMARTS is a screening tool, not FID-grade. Economics are indicative; capex classes are analog ranges.
- The proprietary ECLIPSE E100 solver is not run here; the engine reads existing simulation results via
resdataand falls back to analytical-only when no model exists. To locate bypassed oil precisely, re-run the model with region summary keywords (the assurance agent flags this gap). - NCS fiscal terms (78% default) are configurable and dated — verify against the field's licence vintage before relying on them.
- Geomechanics, drilling, seismic inversion, compositional EoS — named and routed in the agent skills, not solved by the engine.
MIT — see LICENSE. The Volve dataset (Equinor) and libraries used (pyResToolbox, pyscal, resdata) retain their own licences; download data and dependencies separately.