Multimodal Filesystem Memory for Long-Horizon Embodied Agents

Chloe Su*,1,2 Jiahan Li*,3 Zhenting Qi1 Chaoran Cheng4 Haoyu Chen1 Sejoon Jun5 Weirui Ye6 Yilun Du1,2

1Harvard   2Kempner Institute   3NYU   4UIUC   5NEU   6MIT*Co-lead

Paper Code How it works Results

21 of the 24 milestones. Our agent, MFM with Claude Opus 5.5, playing Ender Dragon: 64 minutes of play shown at twice the speed. Click a lit milestone to jump to it. A separate hill-climbing experiment. This video is not one of the paper's main results, which cap each life at 36,000 steps (see Results). Here we raised the cap to 80,000 steps per life and continued the chain to a fourth life. Each life started with the memory of the lives before it and got the chain's tools back, and the lives in the Nether started at a fortress. We found that the baseline methods had saturated, while MFM still had room to improve with a larger step budget and more lives.

IWhy long games need memory

We give an LLM a Minecraft world. It sees the world only as first-person frames and plays in turns: each turn it looks at the newest frame and writes a short list of raw keyboard and mouse actions, which the environment then executes. In the Ender Dragon task it has a budget of 36,000 steps, about half an hour of game time, to work through 24 milestones, from the first log to the dragon. Most of what makes this hard comes down to memory.

What it needs is out of view

The agent walks past an iron vein early on and needs it thousands of steps later, long after the vein has left the screen and the model's context.

Mistakes compound

Each milestone builds on the ones before. Dying in lava loses everything it carries, and the same lake will kill again unless the agent remembers it.

Skills are learned in play

No one gives it a procedure, not for tunneling or fighting a blaze, and not even for walking to a block. It has to notice what worked and save it in a form it can reuse, in this life and the next.

Without memory, all three models we tried stall at about six of the 24 milestones. So the question is what to keep from such a long game, and how the agent can find it again when it matters.

IIHow agents remember

Agent memory has gone through a few designs. We compare them on one question from our runs: in its first life, the agent finds an iron vein deep underground, and tens of thousands of steps later, in its next life, it needs iron again. Where was the vein?

  1. 1

    Context window

    The model reads the recent past straight from its prompt.

    KeepsThe last few frames and messages.

    Finds things byReading its prompt.

    LosesEverything older than the window.

    The iron veinGone. It left the window tens of thousands of steps ago.

  2. 2

    Text memory

    The agent writes notes, summaries or a log, and searches them by keyword or similarity.

    KeepsWhat the agent put into words.

    Finds things bySearching the text.

    LosesWhat it didn't write down, and what anything looked like.

    The iron veinIts coordinates, if it wrote them down, but not what the way in looks like.

  3. 3

    Frame memory

    Every frame is kept, so the agent can look at it again.

    KeepsEverything it saw.

    Finds things byTurn or frame number.

    LosesNot the frames but the way back to them: it has to know when it saw the thing.

    The iron veinIn there, somewhere among thousands of frames.

  4. 4

    Multimodal filesystem memory

    MFM files each frame it records under cues and keeps what the agent learns next to it.

    KeepsThe frame, state and outcome of every action, indexed by when, where and what happened, plus the agent's own facts, procedures and plan.

    Finds things byA query on the cues, then a look at the frames.

    LosesNothing it recorded. Its notes can be wrong, so each one cites the episodes it came from.

    The iron veinAsk for the place, open the frame, set it beside the live view.

Text is easy to search but loses what things looked like; raw frames keep everything but are hard to search. In MFM we keep the frames and put a small text index on top of them, so a short query leads back to the full picture, and the agent files what it learns next to that evidence.

For the filesystem aspect specifically, the useful properties are persistence across sessions, selectively opening large artifacts, updating separate object/task records, and sharing evidence across agents. Simply remembering “I already placed three blocks” motivates memory, but gives little reason to require a multimodal filesystem. Then, we follow our agent back to the iron vein.

IIIHow MFM works

We store the agent's memory as plain files in its workspace, sorted into the five kinds of memory in Figure 2 of our paper. The harness, the program that runs the environment for the agent, writes two of them as the agent plays: episodic memory, one episode per action with its frame, state and outcome and a row of cues in index.jsonl; and spatial memory, a grid of where the agent has been. The agent writes the other three itself: semantic notes, procedures it can call as actions, and a working plan. In its first life all three start empty. We give it no procedures and no reflexes, the guards that watch a plan while it runs, only raw keyboard and mouse actions, so every procedure it calls is one it wrote after seeing how the environment responded. It reads all five with ordinary shell commands during its turn, and the whole directory passes on to its next life.

The figure below replays about 160 steps of one run, the second life of a GPT-6-Astra agent on Ender Dragon. The agent digs down to the iron vein its first life found and mines it at step 8,992; its first life did not reach iron until step 18,231. Every frame, command and file line in the figure comes from the run's record. Stages 1 to 4 make up one turn and repeat; stage 5 comes when a life ends. The figure plays by itself, or click a stage to watch just that part.

Life 2 · step 8,833

Environment Minecraft

The agent's view at step 8,833: the stone wall of the stair it is digging underground.

statex −2953.4  y 18  z −5605.4

Memory filesystem ./

Written by the harness every step, never edited

Episodicepisodes/ · index.jsonl
what happened, and what it looked like
Spatialgrid.jsonl

Written by the agent read every turn, revised as it learns

Semanticmine/GUIDE.md
facts and places
Proceduralmine/procedures/
procedures it can call as actions
Workingmine/working.md
the plan for the next turns

previous/life_1/ · 3,035 episodes

Agent GPT-6-Astra

It searches its memory, looks at the frames it finds, writes down what it learns, and plans its next actions.

actions, executed in the environment

Each turn goes through four stages: the harness records what happened, and the agent retrieves, consolidates and acts. When a life ends, the memory carries over to the next life.

Open step 8,963 in the explorer
The paper's Figure 2, with the files of each kind of memory
Figure 2 of the paper. The environment records every step into the memory filesystem: episodic memory with one directory per episode and an index of cues, and spatial memory with a grid; the agent-written semantic, procedural and working memory under mine/. The agent retrieves by searching cues, locating episodes and inspecting the evidence, and consolidates episodes into knowledge, procedures and a plan.
Figure 2 of the paper.

In the explorer below you can step through whole runs, including this one.

IVExplore a run

We picked 2 of our runs and replay each one together with its memory. Press Play: the run's video plays on the right while the memory on the left fills up. Each box is one kind of memory, in the figure's colors. Click a box or a file to read it as it was at that step, and click it again to go back. The Ender Dragon run is the life from the figure above, which reached 16 of 24 milestones in 36,000 steps.

About this replay

We show the memory as the harness and the agent wrote it: the rows of index.jsonl, the map, the log, and the notes in mine/. Pause or move the step to look at any moment. A query runs over the memory as it stood then, with the rules of the agent's own tool. Everything here is the record of one run, exported by scripts/export_demo.py. Nothing is simulated and no model is called.

  • The index is a file, and the query is a filter. MFM computes no embeddings and ranks nothing. index.jsonl has one row per closed episode, and tools/episodes.py selects rows by step range, by distance from a point, by tag, by action, or by text found in the episode's files. Filters combine with AND, and results come back in the order they were recorded.
  • The query box runs a port of that tool. It was checked against this run: each episodes.py call the agent made was re-run over the index as it stood at that turn and compared, line for line, with the output the run recorded.
  • Replaying the harness's files is exact. The index, the grid and the log are append-only and every row carries its step, so the memory at step s is the rows written by step s.
  • The agent's own files are rebuilt from its patches. The run keeps only the final mine/ files. Their history here comes from the apply_patch calls in the session record, and is shown only when replaying those patches gives back the final file exactly.
  • The video is the run's own recording, one frame per step. The page takes its step from the frame on screen, so the memory on the left is always the memory at the moment the video shows.
  • Frames are reduced. The stored frames are PNG; the page shows JPEG copies no larger than 320×180. Recorded command output is cut at 6,000 characters. Reference and skill files, and images the agent made, are listed and not included.
  • The tool differs between runs. Each run carries its own copy of tools/episodes.py, and the query box accepts the flags of the copy the chosen run had. Where a run carried the memory of earlier lives, the export has the index of those lives and not their episode files, so --previous returns their rows without the harness notes.
  • One run. Each entry in the list is a single recorded life. It shows how the memory is built and read, and says nothing about how often the agent succeeds.
Loading the run…

VResults

We compare MFM with the same agent without memory (Direct) and with two recent memory systems for long-horizon agents, PRO-LONG and VISTA, each on three models. In Minecraft (MCU-AgentBeats), Mine Diamond from Scratch has 10 milestones in a budget of 12,000 steps, and Ender Dragon has 24 milestones in 36,000 steps. In CUABench-KiCad, the agent designs and edits circuits in a desktop app through screenshots, mouse and keyboard, and each task is scored from 0 to 1. We ran every setting with three seeds; bars show the mean and whiskers one standard deviation.

Mine Diamond milestones reached, of 10
Table
ModelDirectPRO-LONGVISTAMFM
GPT-5.6-Sol4.0 ± 1.08.0 ± 1.09.3 ± 0.69.7 ± 0.6
Claude Opus 56.0 ± 1.08.0 ± 1.08.7 ± 0.69.3 ± 0.6
GPT-6-Astra6.3 ± 0.69.3 ± 0.69.7 ± 0.610.0 ± 0.0
Ender Dragon milestones reached, of 24
Table
ModelDirectPRO-LONGVISTAMFM
GPT-5.6-Sol6.0 ± 1.08.3 ± 0.69.0 ± 1.010.7 ± 0.6
Claude Opus 56.0 ± 1.08.0 ± 1.08.7 ± 0.613.3 ± 0.6
GPT-6-Astra6.3 ± 0.611.0 ± 1.012.7 ± 0.615.0 ± 1.0
KiCad mean reward over the tasks, from 0 to 1
Table
ModelDirectPRO-LONGVISTAMFM
GPT-5.6-Sol0.240 ± 0.0260.306 ± 0.0140.400 ± 0.0110.413 ± 0.009
Claude Opus 50.240 ± 0.0230.300 ± 0.0160.373 ± 0.0130.389 ± 0.010
GPT-6-Astra0.267 ± 0.0210.375 ± 0.0120.400 ± 0.0100.440 ± 0.013

MFM has the highest mean with every model on every task, and the gap is widest on Ender Dragon, the longest task. With GPT-6-Astra it reaches all 10 Mine Diamond milestones, and 15.0 of 24 on Ender Dragon, where the best baseline averages 12.7. On KiCad it averages 0.440 with GPT-6-Astra, against 0.400 for the best baseline and 0.267 without memory.

In the next two sections we look at where these gains come from: how the agent uses the frames it keeps, and the skills it writes for itself and carries from one life to the next.

VILooking back at past frames

The index leads the agent to the right episode, but what it checks is the frame. Our agents often open past frames, from the current life and from earlier ones: episodes.py --then-now puts a past frame beside the live view, and zoom.py crops a frame for a closer look. Below, we marked five of these looks on one life's milestone staircase. Point at a callout, or focus it, to enlarge its pair of frames and read what the look changed.

Milestone staircase of an MFM life on the Ender Dragon task with GPT-6-Astra, reaching 16 of 24 milestones within 36,000 steps. Five callouts pair a recorded frame with the later moment an agent retrieved it.
Five times the agent looked back. The staircase is an MFM life on Ender Dragon with GPT-6-Astra, 16 of 24 milestones within the 36,000-step budget. Each callout, at the step it happened, pairs a frame the memory recorded with the moment it was retrieved, and says what the look changed: centering over a hole it was straddling (a), replacing an aiming procedure that had pitched wrong (b), not attacking a wolf (c), digging in at an iron entrance recorded in an earlier life (d), and identifying a sheep as food (e).

Looking back tells the agent what is there. The same memory also holds what it has learned to do: skills it writes for itself and passes on to the next life.

VIISelf-improvement through skill learning

The model's weights never change, so an MFM agent can only get better through what it writes down. Part of that is facts, such as where the iron is. The other part is skills: when a sequence of actions has worked, the agent saves it as a script under mine/procedures/ and from the next turn calls it as a single action. A first life starts with no scripts at all. When a life ends, we pass its records and these files on. This section follows the skills in three steps: how one life writes them, what the next life in the same world gains from them, and what happens when they are handed to an agent on a new task in a new world.

How a skill is written

We followed one chain of two lives with GPT-6-Astra on the Ender Dragon task; the second life is the one in the figure above and in the explorer.

Saved after it works

The agent writes a skill only after doing the thing by hand. Life 2 cleared a stone wall twice before keeping the method: "Save the clearing sequence after its second successful trial."

Guarded by its own checks

Each script first reads the game state and does nothing where it was not tested. descend_one returns no actions unless the inventory screen is closed and the camera is at pitch 60.

Inherited and revised

A later life starts with the earlier life's scripts, reads them, and drops what no longer fits. Life 2 kept 20 of life 1's 21 procedures and retired level_step, the one life 1 had called most, after tracing life 1's fall into lava to it.

The skills of one life

These are the 12 skills of the agent's own writing that life 2 called. Point at a skill, or focus it, to watch one of its calls from that life.

SkillWhat it doesWrittenCalls in lives 1, 2
clears an upper and a lower stone block while standing still, then inspects the floorlife 2, step 25,253—, 94
mines an upper and a lower block of a west wall and collects the dropslife 2, step 2,416—, 86
cuts one descending stair step and advanceslife 2, step 5,249—, 61
the same as quarry_west_pair, heading northlife 2, step 16,028—, 27
extends a floor one block north while sneakinglife 13, 10
clears an upper and a lower andesite block while standing stilllife 2, step 27,581—, 6
raises a cobblestone pillar under itself, then looks aroundlife 10, 5
clears three upper gravel blocks while standing stilllife 2, step 24,628—, 3
jumps up an inspected staircaselife 116, 3
steps down onto an inspected landing one block lowerlife 12, 2
walks down an inspected staircaselife 110, 1
mines a shallow descending step and advanceslife 125, 1

Of life 2's 299 calls to them, 277 went to six skills it wrote during the life, nearly all for digging: clear_west_safe (94 calls), quarry_west_pair (86) and cut_step (61) lead. The other 22 went to six skills it inherited from life 1. It kept the rest of life 1's procedures without calling them, and wrote three more that it never called.

What the next life gains

With the records and the skills carried over, the second life got further within the same budget.

Two lives of one chain milestones reached against steps played
Table
MilestoneLife 1Life 2
Log685332
Crafting table1,451834
Wooden pickaxe1,593954
Cobblestone3,1421,417
Stone pickaxe3,3961,702
Iron ore18,2318,992
Furnace4,8202,416
Iron ingot18,7859,665
Iron pickaxe19,1859,971
Diamond ore34,32117,484
Diamond34,83217,494
Diamond pickaxe35,07117,666
Diamond sword—26,201
Obsidian—20,736
Flint and steel35,31217,951
Netherrack—35,828
Blaze killed, and the seven after it——
Episodes carried in03,035
Last step35,99935,999

Within the 36,000-step budget, life 1 started from an empty memory and reached 13 milestones. Life 2 started with life 1's 3,035 episodes and reached 16, adding the diamond sword, obsidian and netherrack. It also reached everything life 1 had in about half the steps: iron at step 8,992 against 18,231, from the vein in the figure, and its first diamond at step 17,494 against 34,832, five blocks from the place its guide had recorded from life 1.

Skills on a new task

In one world, a skill and the memory of the map arrive together. To look at skills alone, we gave agents three short tasks in a world no earlier life had seen. In one row the agent starts with nothing; in the other it starts with scripts an earlier life wrote, already installed. Each video is one whole life at game speed; the Climb Out lives are played in the dark and are brightened here. For each task we show the slowest life without carried skills beside the fastest life with them, so the pairs show the widest gap we saw and not the typical one. Under each task are the skills involved; point at one to watch it run.

Iron Shield

The agent starts with a stone pickaxe, a crafting table, cobblestone and logs, and is told where a vein of iron ore lies, 13 blocks below. It must build a furnace, dig to the vein, smelt an ingot and craft a shield.

  • The life with carried skills called it once and went 13 blocks down to the vein in one action; the life without dug down with mine_ahead, 35 calls.
No carried skill. Shield at step 3,260.
With the scripts of a two-life Diamond chain. Shield at step 1,105.

Climb Out

The agent starts sealed in a pocket 40 blocks underground with a stone pickaxe and eight cobblestone, and must reach the surface and mine a block of bricks set straight above it.

  • Written in a published Ender Dragon life and carried in with stair_up and three others. This life called it twice at the start, rose three blocks, then kept climbing the same way by hand.
  • The life without carried skills climbed with it, 20 calls between 61 of mine_ahead.
No carried skill. Bricks mined at step 2,483.
With the scripts of an Ender Dragon life. Bricks mined at step 1,665.

Cook Meat

The agent starts with a stone sword, a stone pickaxe, a crafting table, cobblestone and logs, with three cows nearby, and must build a furnace, kill an animal and cook its meat.

No carried skill. Cooked meat at step 771.
With the fight loop. Cooked meat at step 428.

VIIIBeyond Minecraft: computer use

Nothing in MFM is specific to a game. We ran the same memory on CUABench-KiCad, a computer-use benchmark in which the agent edits and designs circuits in the KiCad desktop application, seeing only screenshots and acting with mouse and keyboard. Its 25 tasks run one after another in the same application, and the agent starts each one with the records and notes of the tasks before it. With GPT-6-Astra, MFM averages a reward of 0.440, against 0.400 for the best baseline and 0.267 without memory (see Results).

Below is one recorded run of MFM with GPT-6-Astra, task by task. A task's reward is the share of three checks its saved netlist passes against a reference: the components, the connections and the net names. Open a replay to step through the screenshots the agent saw, with what it said and did at each step and what its memory gave it: the earlier situations recalled for it, and the notes and records it opened.

CUABench-KiCad · MFM
GPT-6-Astra
one recorded run, in the order it ran
Mean reward
–
Solved
–
Partly solved
–
Steps taken
–
Status Replay
Loading the run…

This is a single run, one of the task orders behind the mean above; the tasks are listed in the order the agent took them. The task titles are ours; the benchmark names tasks by id. A step cap of 200 applied, and the agent ended every task itself.

Task

What the agent saw

Its plan

Actions, marked on the screen

    From memory at this step

    Notes it wrote during this task

    Cite

    @misc{su2026mfm,
      title  = {Multimodal Filesystem Memory for Long-Horizon Embodied Agents},
      author = {Su, Chloe and Li, Jiahan and Qi, Zhenting and Cheng, Chaoran and Chen, Haoyu and Jun, Sejoon and Ye, Weirui and Du, Yilun},
      year   = {2026},
      note   = {Project page: https://github.com/Hither1/MFM}
    }