Earth & Environmental Computing · Week 10 · Course session · 44 slides
Download HTML
Earth & Environmental Computing | Computational Methods for Earth & Environmental Science | 16-Week Course

Agentic AI Coding for Earth Science

The unit of work is no longer a line of code. It is a verifiable scientific task.

Week 10·Course session·From Prompts to Reproducible Scientific Workflows
Cold open

A 20-Minute Coding Task in 90 Seconds

A real session against demos/earth-agent-demo, replayed at reading speed. Every command and every line of output actually ran.

The shift

The Unit of Work Has Changed

Then

Autocomplete

next token

You write every line. The tool guesses the end of the one you are on.

Recently

Chat assistant

question → code

You paste a question, read an answer, and paste the code back yourself.

Now

Coding agent

goal → inspect → plan → act → run → observe → iterate

You state an outcome. It works in the repository until the evidence says it is done.

We are moving from writing code with AI to supervising AI that works on code.

Learning Objectives

By the End of This Lecture, You Will Be Able To

  • Describe what a coding agent is, and what its loop does at each step
  • Write a repository context file that states your scientific conventions
  • Define a task as a contract: goal, context, constraints, evidence, stop
  • Place a check at the right level of the verification pyramid
  • Say which scientific decisions you may not delegate, and why
Contents

Today's Lecture

01Anatomy of a coding agent
04Scientific verification
02Context and task engineering
05Scaling agentic work
03A real session, step by step
06Scientific responsibility
Recap

Last Week in Sixty Seconds

  • Pseudocode before Python: get the logic wrong on paper, not in code
  • A centred window and a trailing window answer different questions
  • Three rungs of verification: it runs, it reproduces, it is defensible
  • Today: hand the typing to an agent and keep every one of those rungs
Materials

Today's Repository

PathWhat it isWhy it is there
demos/earth-agent-demo/A small streamflow project, two water yearsThe repository the agent works in today
docs/SCIENTIFIC_CONTEXT.mdUnits, water year, missing-value rule, invariantsWhat the agent must read before it edits
src/streamflow.pyFour summaries and a plotRuns clean; four of its answers are wrong
tests/test_streamflow.pyFive tests, all greenGreen tests that catch none of the four
01

Anatomy of a Coding Agent

Not a mystery. A model that can look at the world, pick a tool, and look again.

01 · Anatomy

What Makes an AI Agentic?

Coding agent  =  Model + Context + Tools + Environment + Feedback loop + Permissions

It observes

It reads files, output and errors from a real environment, not from your message.

It chooses

At each step it picks the next tool. That choice is the whole of the "agency".

It continues

The result of one step becomes the input to the next, until a stop condition is met.

01 · Anatomy

The Scientific Agent Loop

Inspectread beforeyou touchPlanpropose, thenwaitActone changeat a timeRunexecute itfor realObserveread whatcame backVerifyagainst areferenceRecordwhat changed,and whyuntil the evidence says it is doneA software agent loop stops at ObserveScience needs these two as well

A software agent loop stops at Observe. Verify and Record are what make it usable for science.

01 · Anatomy

What Tools Can an Agent Use?

Modelchooses thenext toolFilesShellGitTestsNotebookDocsAPIsMCPThe model never opens a file. It decides that opening a file is the next move.
01 · Anatomy

Three Products, One Mental Model

Claude CodeCodexGitHub Copilot
Project contextCLAUDE.mdAGENTS.mdcopilot-instructions.md
Plan before actingPlan modePlan modePlan mode
Acts throughShell, edit, git, MCPCLI, IDE, cloudIDE, CLI, GitHub
Extends withSkills, hooks, subagents, MCPSkills, subagents, MCPSkills, custom agents, MCP
Learn the primitives, not the product. All three read a context file, plan, call tools, and can be extended the same four ways.
02

Context and Task Engineering

Good agentic coding is less about clever prompting than about a well-built work environment.

02 · Context and task

Prompt Engineering Is Not Enough

What you writeWhat you can check afterwards
WeakFix my analysis.Nothing. You cannot tell whether it is done.
BetterRead analysis.py, find the bug, fix it.That a bug was found. Not that it was the right one.
A contractOutcome, constraints, boundary, evidence, stop condition.Every clause, one at a time.
02 · Context and task

An Agent-Ready Task Is a Contract

Goal → Context → Constraints → Evidence → StopGoalWhat must be true when this is doneAnnual means use the water year and match the reference.ContextWhat the agent must read firstdocs/SCIENTIFIC_CONTEXT.md, and the existing tests.ConstraintsWhat may not changeRaw data are immutable. Missing stays NaN. Discharge is cfs.EvidenceWhat will show it workedpytest green, and WY2018 reads 2,418.0 cfs.StopWhen to stop and askIf the repository cannot settle a convention, report what is missing.

Five words to carry out of this lecture: Goal, Context, Constraints, Evidence, Stop.

02 · Context and task

Teach the Repository, Not the Prompt

docs/SCIENTIFIC_CONTEXT.md

## The Water Year

The water year begins on October 1 and is named for the calendar year it
ends in. Water year 2018 runs 2017-10-01 to 2018-09-30.

Annual summaries in this project use the water year. On this record the two
conventions disagree by nearly a factor of two for 2018.

## Missing Observations

Missing discharge stays NaN. It is never filled with zero, and never
interpolated unless a human asks in writing and the choice is recorded.

Zero is a real discharge: it means the channel is dry.
  • Written once, read by every agent and every new student
  • An agent that has not read this will write code that runs and is wrong
  • CLAUDE.md, AGENTS.md and copilot-instructions.md all point here, so there is one copy
02 · Context and task

An Earth Science Agent Needs More Than Coding Style

Units

discharge in cfs; 1 cfs = 0.0283168 m3/s; elevation in metres above NAVD88.

Time

Water year from October 1. Local standard time. No daylight saving.

Missing

NaN stays NaN. Zero means a dry channel, not an absent sensor.

Invariants

Raw data immutable. No interpolation without a written request.

"Use PEP 8" tells an agent how to format the mistake. These four tell it not to make it.
Pause and think

?

Your agent has no scientific context file. You ask it to compute annual means from a daily record. What will it almost certainly do, and will anything complain?

It will group by calendar year, because that is what dt.year gives and what most code on the internet does
Nothing will complain: the code runs, the tests pass, and the number is wrong by nearly a factor of two
03

A Real Session, Step by Step

Can an agent improve this analysis without changing the science?

03 · The session

Passing Tests, Failing Science

$ python -m pytest tests -q
.....                                        [100%]
5 passed in 0.73 s

$ python -c "import streamflow; print(streamflow.annual_mean(df).loc[2018])"
4195.4   cfs     the record says the answer is 2418.0

Five green tests, and the number is 74 per cent too high. The suite checks shapes and exceptions. Nobody wrote a test for the year convention, because the person who wrote the tests had the same misunderstanding as the code.

03 · Inspect

Step 1: Read Before You Touch

The task given to the agent

Inspect this repository. Explain the analysis workflow and identify the
scientific assumptions it makes. Do not edit anything.

What came back

read  docs/SCIENTIFIC_CONTEXT.md
      water year begins October 1
      missing discharge stays NaN, never zero
read  src/streamflow.py
grep  'fillna|dt.year|m3/s'
      line 14  .fillna(0)           contradicts the missing-value rule
      line 20  .dt.year             calendar year, not water year
      line 38  'Discharge (m3/s)'   the values are cfs
      line 47  .dt.year again       the same decision, duplicated
03 · Plan

Step 2: Separate the Two Kinds of Change

Software. Go ahead.

  • Relabel the axis to cfs
  • Remove the duplicated grouping
  • Make the data path work from any folder

Scientific. Ask first.

  • Switch annual means to the water year
  • Stop filling missing days with zero
  • Decide what a year with a ten-day gap should report
The agent proposes both lists. You approve the right-hand one, one line at a time.
03 · Act and run

Step 3: One Change, Then Run It

The safe change first

- ax.set_ylabel("Discharge (m3/s)")
+ ax.set_ylabel("Discharge (cfs)")

$ python -m pytest tests -q

Output

.....                                [100%]
5 passed in 1.24s
  • The label was wrong by a factor of 35 and no test could ever have caught it
  • One edit, one run. A batch of ten edits with one test run tells you nothing about which one broke it
03 · Observe

Step 4: The Science Got Better and the Test Went Red

The approved scientific change

+ def water_year(dates):
+     return dates.dt.year + (dates.dt.month >= 10)

- return df.groupby(df["date"].dt.year)[...].mean()
+ return df.groupby(water_year(df["date"]))[...].mean()
- df["discharge_cfs"] = df["discharge_cfs"].fillna(0)

$ python -m pytest tests -q

Output

    def test_annual_mean_returns_one_value_per_year(df):
        result = streamflow.annual_mean(df)
>       assert len(result) == 3
E       assert 2 == 3

1 failed, 4 passed
Pause and think

?

You made the code scientifically correct and a passing test started failing. Which one is wrong, the code or the test?

The test. It asserted three groups because it was written against calendar years
The record spans two water years, 2018 and 2019, so two is the right answer
A test can encode a bug. Reverting the science to keep a suite green is how a wrong result survives
03 · Verify

Step 5: Put the Science Into the Test

tests/test_streamflow.py

def test_annual_mean_uses_water_years(df):
    # 2017-10-01 to 2019-09-30 is water years 2018 and 2019.
    # Three groups would mean it is grouping by calendar year.
    result = streamflow.annual_mean(df)
    assert list(result.index) == [2018, 2019]
    assert result.loc[2018] == pytest.approx(2418.0, abs=0.1)


def test_missing_days_are_skipped_not_zeroed(df):
    # Ten days are missing in June 2018. Filling them with zero
    # would pull the water-year mean down to about 2351.8 cfs.
    assert streamflow.annual_mean(df).loc[2018] > 2400
  • The suite now states a scientific fact, not a shape
  • 6 passed. The next person to break the water year will be told exactly what they broke
03 · Review

Step 6: What Did It Leave Behind?

git diff, read in full

$ python -c "print(annual_mean(df).round(1).to_dict())"
$ python -c "print(summary_table(df).set_index('year').mean_cfs.round(1).to_dict())"

Output

annual_mean    {2018: 2418.0, 2019: 5764.3}
summary_table  {2017: 664.2, 2018: 4313.5, 2019: 5018.2}

6 passed
Two functions in one module now answer the same question differently, and the suite is green. The agent fixed what it was pointed at.
03 · Review

What the Agent Could and Could Not Know

It could know

  • The structure of the code and the column names
  • Which tests fail, and the traceback
  • Every rule in the context file you wrote
  • That two functions now disagree, if asked to look

It could not know

  • Whether the sensor was trustworthy that June
  • Whether 419 m3/s is plausible for this reach
  • Whether filling the gap is defensible here
  • Whether the result supports the claim you want to make
04

Scientific Verification

Passing tests is not the same as being scientifically correct.

04 · Verification

The Scientific Verification Pyramid

5 · InterpretationDoes the result support the claim?the scientist, alone4 · PhysicalIs it possible? 419 m3/s, not 4,188.the scientist decides3 · DataUnits, time, coordinates, missing values.shared2 · NumericalDoes it reproduce a known number?mostly the agent1 · SoftwareDoes it run? Do the tests pass?the agentresponsibility moves to the scientist

Agents help at every level. Responsibility moves to you as you climb.

04 · Verification

Earth Science Has Its Own Silent Errors

Silent errorWhat it looks like in our own data
Unitscfs read as m3/s: the 2018 peak becomes 419 instead of 14,800
CalendarCalendar year where the water year was meant: 4,313 against 2,418 cfs
Missing valuesTen absent days filled with zero: every mean containing them drops
CoordinatesLatitude and longitude swapped, or 0-360 against -180-180
Vertical sign, projectionElevation against depth; two layers in different systems
Time and scaleUTC against local; a satellite product used without its scale factor
None of these raises an exception. Every one of them changes the answer.
04 · Verification

Create the Evidence Before You Delegate

Python

reference_monthly = (stream.assign(month=stream["date"].dt.to_period("M"))
                     .groupby("month")["discharge_cfs"].mean())
reference_annual = (stream.assign(year=stream["date"].dt.year)
                    .groupby("year")["discharge_cfs"].mean())
print(reference_annual.loc[2018:2020].round(1).to_string())

Output

year
2018    4263.5
2019    4712.1
2020    2775.8
  • Computed before any agent edits anything, with code you can explain line by line
  • Every AI-assisted change has to reproduce it exactly, or explain why not
  • Write one number on the board: 2018 averaged 4,264 cfs on the full record
04 · Verification

A Tiny Test Is Manufactured Scientific Truth

Python

tiny = pd.DataFrame({
    "date": pd.to_datetime(["2030-01-01", "2030-01-02", "2030-01-03", "2030-02-01"]),
    "discharge_cfs": [100.0, 300.0, np.nan, 50.0],
})
by_month = (tiny.assign(month=tiny["date"].dt.to_period("M"))
            .groupby("month")["discharge_cfs"])
print("mean: ", by_month.mean().tolist())
print("count:", by_month.count().tolist())
assert by_month.mean().loc["2030-01"] == 200.0

Output

mean:  [200.0, 50.0]
count: [2, 1]
  • Four rows you worked out by hand, where you already know the answer
  • It pins the convention: January averages two days to 200, not three to 133
  • Week 4's habit, pointed at a new source of code
Pause and think

?

np.allclose says the monthly values match the reference. assert_series_equal says they do not. Which do you believe?

Both. The numbers match and the index changed from months to dates
allclose checks numbers; assert_series_equal checks what the code downstream relies on
Decide whether the index matters, then either keep it or change the reference on purpose and record it
05

Scaling Agentic Work

Six ways to give an agent more reach, and one way to fool yourself with them.

05 · Scaling

Beyond One Agent

Instructions

Project knowledge that persists, so you stop repeating yourself.

Skills

A procedure you wrote once, reused whenever it applies.

Hooks

A deterministic check that runs every time, whatever the model decides.

MCP

A bridge to outside tools and data: a catalogue, a database, an instrument.

Subagents

A bounded task in its own context, so one long job does not crowd out the rest.

Parallel work

Separate worktrees, so two changes cannot overwrite each other.

05 · Scaling

When Parallel Agents Help, and When They Lie

  • Genuinely useful: one agent on data checks, one on numerical tests, one on the record of what was done
  • They are useful because the tasks are independent, not because there are three of them
  • Five agents agreeing is not five pieces of evidence: they share a model, a prompt and a blind spot
  • Agreement between an agent and a measurement is evidence. Agreement between agents is a correlation
Multi-agent agreement is not independent scientific evidence.
05 · Scaling

From Prompt to Scientific Workflow

01

Scientific question

02

Task contract

03

Repository context

04

Agent loop

05

Code and computation

06

Verification

07

Scientific interpretation

08

Record of what was done

The agent owns 04 and 05. You own 01, 02, 06, 07 and 08. Steps 6 to 8 are in accent because they are the ones a software course leaves out.

06

Scientific Responsibility

What to hand over, what to keep, and how to say which you did.

06 · Responsibility

What Should You Delegate?

Low scientific judgmentHigh scientific judgmentboilerplaterenamingdocstringstest scaffoldingrepository searchwhich years to keephow to treat a gapuncertainty assumptionswhich hypothesiswhat the result meansHand it over on the left. Own it on the right.The line does not move because the model improved. It moves when you can defend the answer.
06 · Responsibility

The Policy, and an Honest Log Entry

Log fieldExample entry, Group Lab 4
PurposeMove the annual summary onto the water year
PromptRead the repository, list contradictions with the context file, propose a plan, do not edit
How verifiedpytest green, plus WY2018 == 2418.0 against the record
Changed by handRewrote the test the agent wanted to delete
RejectedIts offer to interpolate the June gap; the context file forbids it
Allowed for debugging, refactoring, tests and documentation. Disclosed every time. You must be able to explain every line you submit.
06 · This week's lab

Group Lab 4: Agentic Coding on a Broken Repository

Lab session

  • Clone demos/earth-agent-demo with its bugs intact
  • Write the task contract before touching anything
  • Fix one software issue and one scientific issue

Studio session

  • Add a test that encodes a convention from the context file
  • Find the fourth bug nobody has fixed yet
  • Hand in the AI usage log with one rejected suggestion
Summary

The New Skill Is Supervision

  • An agent observes, chooses a tool, and acts on the result: inspect, plan, act, run, observe, verify, record
  • Put your conventions in the repository, not in a prompt
  • Define the task as a contract: goal, context, constraints, evidence, stop
  • A green suite is level 1 evidence; units, time and missing values live at level 3
  • AI does not remove the need to understand code. It changes what that understanding is for
Agents manipulate code. You own the science.
Discussion · Next week: geostatistics and spatial prediction

?

Name one convention from your own field that an agent would get wrong without being told. What would you write in the context file?

Take three answers and write them on the board
Those sentences are the first draft of a context file for their final project