data/
data/ is the durable storage root for everything that grows, changes, or gets written
during execution — material the agent accumulates over time rather than authored behavior.
data/
├── knowledge/ # reference material the agent reads
├── modules/ # module-managed persistent state
└── workspace/ # scratch space: cloned repos, working trees, temp output
.agent/data/ # written by the runtime, not by you
├── sessions/ # thread history — written by Axon
├── state/ # persistent working state across sessions
└── sensory/ # dense sense streams, when the agent has sensors
Two roots, and the line between them is who wrote the file. data/ is yours —
you author it, you commit it, it is part of what the agent is. .agent/data/ is the
runtime's — a record of what the agent did, generated rather than written, and
gitignored along with the rest of .agent/.
That is why sessions/ and state/ moved out of data/ and knowledge/ did not: a
session log is output, a knowledge file is input. Everything under .agent/ can be
deleted and the agent is still the same agent; delete data/knowledge/ and it is not.
Keep the distinction clean: if a file tells the agent who it is or how to behave, it
belongs in src/. If it is durable material the agent consults or writes during work, it
belongs in data/. If the runtime produced it, you do not place it at all.
AXON_HOME
Every agent gets AXON_HOME injected automatically — the absolute path to its own
directory, the folder holding axon.config.ts.
Agent code also RUNS there. The working directory is the agent's own root, wherever the command was invoked from, and it is the same directory the agent has deployed — so a relative path behaves identically in both places:
await fs.read("axon.config.ts") // relative to the agent root
await fs.read("data/knowledge/notes.md") // the same, from anywhere you ran it
AXON_HOME is for the cases where a relative path is not enough — building an absolute
path to hand to a subprocess, or a tool that changes directory:
const knowledge = `${process.env.AXON_HOME}/data/knowledge`
const state = `${process.env.AXON_HOME}/.agent/data/state`
This means agents always know where home is — in local dev, in deployment, across reboots.
knowledge/
Reference material the agent can read. Commit anything here that should be available across sessions: architecture docs, API contracts, codebase conventions, runbooks, decision logs.
data/knowledge/
├── decisions/
│ ├── 2025-05-auth-flow.md
│ └── 2025-06-db-schema.md
├── api-contracts.md
├── architecture.md
└── conventions.md
The agent doesn't automatically read everything in knowledge/ — a prompt or script
directs it to read specific files when relevant. The value is having authoritative
reference material on disk, in the repo, versioned with the codebase.
In the .agents/ workspace layer, data/knowledge/ is the canonical location for
project-level reference material shared across all agents in the repo.
.agent/data/sessions/
Written entirely by Axon. Thread logs, conversation history, and continuity data live here, organised by session and thread ID.
.agent/data/sessions/
└── <session-id>.jsonl
Don't write to sessions/ manually. Don't depend on its internal structure in your code.
Axon manages it — the format may change between versions. Its position under .agent/
is the same statement: this is generated output, not part of your source.
.agent/data/state/
Persistent working state the agent writes and reads across sessions. Use this for anything that needs to survive a reboot but isn't reference material — scan results, open proposals, sync cursors, computed summaries.
.agent/data/state/
└── <cognet>/
├── coverage.json # last known coverage snapshot
└── proposals.json # open proposals awaiting human review
Unlike sessions/ (managed by Axon) and knowledge/ (written by humans), state/ is
owned by the agent. It reads and writes it freely as part of its work. It lives under
.agent/ because the agent produced it — but unlike the rest of that directory, deleting
it costs the agent its memory, so it is the one part of the frame worth backing up.
The human can inspect it at any time — keep it in plain JSON or Markdown so it's readable without tooling.
workspace/
The agent's scratch space. Clone repos here, check out working trees, write intermediate output, run builds. Anything that needs a real filesystem path during a work session.
data/workspace/
├── audit-output/ # intermediate files from a multi-step run
└── my-target-repo/ # cloned for the current task
Think of it as the agent's equivalent of a developer's ~/projects/ — a place to put
things being actively worked on. Use AXON_HOME to anchor paths here:
const repoPath = `${process.env.AXON_HOME}/data/workspace/my-target-repo`
await process.run(`git clone https://github.com/org/repo ${repoPath}`)
workspace/ is not committed. It's ephemeral relative to data/ as a whole — the agent
can treat it as a temp dir that persists across sessions but is safe to delete and
regenerate. Don't put anything irreplaceable here; put irreplaceable output in state/
or knowledge/.
modules/
Module-managed persistent state, namespaced by module name. If an installed module needs to persist data — a cache, a sync cursor, indexed content — it writes here.
data/modules/
└── @axon/
└── github/
└── webhook-cursor.json
Each module owns its subdirectory. Don't write to another module's namespace.
Persistence in deployment
In local agents, both roots are files on disk. In deployed agents on Axon Cloud, they are
backed by durable storage — every write the agent makes inside data/ or .agent/data/
persists across restarts and redeployments.
Self-hosted deployments need to mount persistent storage at both paths to get the same
behaviour. Mounting only data/ is the easy mistake to make and the expensive one: the
agent keeps its knowledge and loses its memory, coming back after every restart with no
session history and no state.
Anything written outside those two roots during execution is ephemeral in deployed
environments. Write durable output to data/; let the runtime write .agent/data/.