Skip to main content
OpenHome Abilities can read and write files that persist across sessions. This is how you build voice journals, running logs, long-term preferences, alarms, grocery lists, and any Ability that needs to remember something beyond the current conversation.
If you specifically need an Ability to influence the Agent’s prompt (inject context the Agent can see), see Agent Memory & Context Injection — that page covers the .md-file → Agent-prompt pipeline. This page is about general-purpose file storage.

The API

Four methods, all from self.capability_worker:
Full method details: SDK Reference.

Storage patterns

Four patterns cover 90% of use cases. Pick the one that matches your data’s shape.

1. Journal / append log

For things that grow forever and don’t need to be read in structured form — voice journals, event logs, debug traces.
Key property: write_file appends by default for text-like files — no read-modify-write needed. Read later:
Never use this pattern for JSON. Appending to a JSON file produces invalid JSON. Use the Key-value JSON pattern instead.

2. Latest state / replaceable file

For a single current value that gets overwritten — user preferences, the latest mood reading, the current “focus mode” flag.
Always delete + write, never append. Then read gives you the current state:
This is also the pattern required for .md context files that inject into the Agent prompt.

3. Key-value JSON

For structured data with multiple fields — alarms, reminders, a grocery list, user settings.
Always delete + write for JSON. write_file() appends by default, which produces invalid JSON and breaks the next read.

4. Rolling window

For recent-N data — last 100 sensor readings, last 24 hours of transcripts, recent commands.
Always trim at write time, not at read time — the file size stays bounded, reads stay fast.

Persistent vs temp

Default to temp=False. Only use temp=True when you need to remember something within a session but want it cleared after.

Best practices

Namespace your filenames

Avoid generic names. They collide across Abilities.
  • data.json, state.md, list.txt
  • smarthub_prefs.json, alarm_active.md, grocery_list.txt
Use the Ability name (or a short prefix) at the start of every filename.

Keep each file focused

One logical object per file. Split a shared concern across files when the single file gets past ~1 MB or starts holding multiple unrelated concepts.

Always check existence before read

read_file() on a missing file throws. Always:

Serialize JSON yourself

write_file() takes a string. Use json.dumps() when writing, json.loads() when reading. Wrap json.loads in a try/except json.JSONDecodeError to recover from corrupt files.

Bound your data

Rolling windows, journal rotation, log truncation — pick a cap and enforce it at write time. Unbounded files fill disk and slow down every future read.

Handle missing files as “first run”

On the first call, every file is missing. Design for that:

When to use main.py + background.py together

If you need to write from main.py and react to that write from a background daemon — like alarms or reminders — see the Coordination Pattern in Background Abilities. Both files read and write to the same shared file storage.

See also