Inspiration

A vessel that passes every conditions test can still lose the mission.

Saronic is valued at $9.25B after a $392M Navy contract for the Corsair USV. Autonomous surface and undersea platforms are becoming core naval infrastructure — and they're still validated by asking whether a hull survives a 6-meter sea state in isolation.

That's the wrong question. Fuel doesn't run out in a wave tank. Fatigue doesn't accumulate across a single test. Stability margin collapses at a specific heading, in a specific sea state, forty hours into a transit — and nothing in a conditions test will ever tell you that. You find out at sea, where the answer costs weeks, six figures, or the platform itself.

We wanted to ask the real question instead: can this vessel, on this route, through the weather that will actually be there, finish the job?

What it does

Give SeaForger four things — a vessel, an origin, a destination, a departure time.

It pulls the forecast. Atmospheric and wave data, sampled at every position and timestep along the route.

It runs the voyage. A Rust physics engine burns fuel, builds waves, accumulates corrosion and fatigue, tracks stability margin — and reports exactly where and how the mission breaks.

It sends an agent to fix it. A Jac agent loop proposes route and speed changes, re-runs the entire pipeline on each candidate, and keeps only what the physics proves is better.

It shows you why. The voyage plays back on a 3D globe with the route, the weather, and failure points marked on the hull.

What comes out is not a forecast. It's a verdict: this plan completes the mission, that one doesn't, and here is the number that separates them.

How we built it

        React + Three.js mission interface
                      │
              Jac agent + mission layer
                      │
            ┌─────────┴─────────┐
            ▼                   ▼
     Forecast pipeline    Rust physics engine
     (GFS / NOAA waves)   (fuel, fatigue, GM, failure)
            └─────────┬─────────┘
                      ▼
             Verified mission result

Jac is the orchestration and agent layer. A mission is a graph — so we modeled it as one. Nodes hold persistent mission state, walkers traverse it and do the work, candidate simulations attach as they're generated.

Four agents run the loop:

Agent Job
Planner Shift a waypoint, cut speed through a rough band, avoid a wave region
Environment Pull the real forecast for that candidate. Never invent a number.
Simulation Run it through Rust — fuel, roll, stability, fatigue, failure risk
Critic Score against current best; accept only if measurably better and legal
Propose → Fetch forecast → Simulate → Score
   │                                    │
   └──────── better & valid? ───────────┘
        yes → new best     no → reject

The model is declared as a typed function via Jac's by llm(), so proposals arrive structured instead of as prose we'd have to parse and trust:

obj RouteProposal {
    has reason: str;
    has waypoint_changes: list[dict];
    has speed_changes: list[dict];
    has expected_effect: str;
}

def improve_mission(
    mission: dict,
    current_result: dict,
    constraints: dict
) -> RouteProposal by llm();

The signature is the contract. Every proposal gets validated against vessel limits before it earns a simulation run — and the model cannot mark a simulation successful, alter measured weather, bypass a limit, or publish an unverified route. It proposes. The physics decides.

Challenges we ran into

Three systems, one mission. Weather lives on geographic grids. A vessel moves continuously through space and time. Every provider names and scales its variables differently. Nothing could reach the physics engine until we built a normalization layer that hands it one stable schema regardless of source.

The AI wanted to be the judge. Getting a language model to describe a safer route takes one prompt. Proving the route is safer means re-running the forecast and the full simulation for every candidate it dreams up. Making that gate non-optional — rather than a step you could skip when the demo clock ran down — turned out to be the whole ballgame.

Deadline honesty. We drew an explicit line between what runs end-to-end and what's groundwork. A small loop you can prove beats a large one you can only describe.

Accomplishments that we're proud of

  • Every agent proposal is tested against real physics before acceptance
  • Genuine multi-agent coordination with an independent judge — not four prompts in a trenchcoat
  • A normalized environment schema that lets forecast sources swap without touching the engine
  • The LLM kept strictly outside the authoritative calculations
  • A 3D interface that shows why a voyage failed, not just that it did

What we learned

AI belongs on top of ground truth, not in place of it. The model is genuinely sharp at reading a failed voyage and proposing a fix — and it has no business deciding whether a hull is stable.

The corollary took longer to internalize: a multi-agent loop is only trustworthy when its judge sits outside the model. Ours is the Rust engine plus the mission's hard constraints. The loop improves only when the number improves.

Jac's graph-and-walker model turned out to be the right shape for exactly this — iterative, stateful, many-candidate evaluation is what walkers over persistent nodes are for.

What's next for SeaForger

  1. Extend the search to material and plating configuration, not just route and speed
  2. Multi-candidate route search with ensemble-forecast uncertainty bands
  3. Fastest / safest / lowest-fuel plans compared side by side
  4. Real ocean currents, salinity, and sea-ice feeds
  5. Full pipeline deployed behind HTTPS for live evaluation

Built With

Share this project:

Updates