Skip to content

Data directory layout

Netclaw keeps everything it owns under one directory: ~/.netclaw, or $NETCLAW_HOME if you set it. In the Docker image that’s /home/netclaw/.netclaw. Use this page to find a file, decide what’s safe to delete, and know what to copy in a backup.

This is the layout after a first start with a few sessions, one reminder and one secret:

~/.netclaw/
├── config/
│ ├── netclaw.json
│ ├── secrets.json
│ ├── tool-approvals.json
│ ├── devices.json
│ ├── webhooks/
│ └── daemon.env
├── keys/
├── identity/
├── skills/
├── agents/
├── sessions/
├── schedules/reminders/
├── jobs/
├── workspaces/
├── netclaw.db
├── models/
├── logs/
├── client/
├── cache/
├── runtime/
├── bin/
├── projects/
├── environment/
├── netclaw.pid
└── netclaw.lock
PathHoldsBack upSafe to delete
config/Settings, secrets and access state. See config/YesNo
keys/The key ring that decrypts secrets.json, one key-<guid>.xml per keyYes, alwaysNo. Without it every stored secret is unreadable, and a daemon with stored secrets fails at startup.
netclaw.dbOne SQLite database: conversation history, the session catalog, durable reminders, usage stats, memory and session storage bindingsYesNo
netclaw.db-wal, netclaw.db-shmSQLite write-ahead log and shared memory, present while the daemon runs and sometimes after it stopsWith the databaseNot while the daemon runs
identity/SOUL.md, AGENTS.md and TOOLING.md plus their soul/, agents/ and tooling/ folders. Your agent’s personality and standing instructionsYes, except tooling/shadow/tooling/shadow/ only. It’s regenerated at startup.
skills/Your own skills. .system/ is managed by the daemon and .server-feeds/ holds synced feed skillsYes, except .system/ and .server-feeds/.system/ and .server-feeds/ come back at the next start
agents/Sub-agent definitions you wrote. .server-feeds/ holds synced onesYes, except .server-feeds/.server-feeds/ re-syncs
sessions/One folder per session created since 0.27.0. See Session storageYesOnly for sessions you’ve finished with
schedules/reminders/One JSON file per reminderYesDeleting a file deletes the reminder
jobs/Background shell jobs: <id>.json and <id>/output.logNoYes, when no job is running. Finished jobs are pruned after 24 hours anyway.
workspaces/Project workspaces, usually git repositories with an AGENTS.md. Moves if you set Workspaces.DirectoryYesNo. It holds your working copies.
models/Downloaded ONNX models for memory, about 129 MBNoYes. The daemon downloads them again at the next start.
logs/Daemon, crash and session logs. See LogsNoYes, once you’ve read what you need
client/config.json, the daemon endpoint this machine is paired toOnly on a paired clientYes. You’d pair again.
cache/Restart bookkeeping such as restart-manifest.jsonNoYes, with the daemon stopped
runtime/The daemon’s working directory. Empty in normal useNoYes
bin/The netclaw and netclawd binaries on a host install. Empty in DockerNoNo on a host. A full reset from netclaw init keeps it.
.bundle/Only if you set DOTNET_BUNDLE_EXTRACT_BASE_DIR into the data directory: the daemon’s unpacked native libraries, about 43 MB. The Docker hardened profile uses a tmpfs insteadNoYes, with the daemon stopped. It’s rebuilt at the next start.
projects/, environment/Created at startup, empty on a fresh installNoYes
netclaw.pid, netclaw.lockProcess id and the singleton lock that stops a second daemonNoOnly a stale pair, with no daemon running
envHost installs only: the shell snippet that puts netclaw on your PATHNoNot unless you uninstall
FileHoldsBack up
netclaw.jsonAll settings. Edits restart the daemon after it drains sessions. See netclaw configYes
secrets.jsonCredentials, encrypted with the key ring in keys/. Written by netclaw secrets set. One exception: Providers.<name>.OAuthTokenExpiry is plain textYes, with keys/
tool-approvals.jsonSaved “Always” approvals. Also .lock and, after an upgrade from an older format, .v2.bakYes
netclaw.json.removed-keys.bak, netclaw.json.legacy-tool-defaults.bak, netclaw.json.retired-oauth-expiry.bakCopies of netclaw.json that netclaw doctor --fix writes before it removes keys or moves a retired OAuthTokenExpiry to secrets.json. A second backup of the same kind gets a number: .removed-keys.2.bakOptional
devices.jsonPaired devices as salted token hashesYes, or you pair again
bootstrap-state.jsonFirst-start bookkeeping for non-local exposure modesYes
hard-deny-overrides.jsonOptional operator hard-deny overrides. Absent unless you made oneYes, if present
webhooks/One file per inbound webhook routeYes
daemon.envsystemd only: the PATH captured by netclaw daemon install. install and netclaw doctor --fix change only the PATH line and keep every other line, such as NETCLAW_HOME=..., as it isYes, if you added lines

netclaw.json can hold only part of your configuration. Variables named NETCLAW_* override it and don’t appear in any file, so keep a copy of how you set them.

Conversation history doesn’t live in sessions/. It’s in netclaw.db. A session folder holds the files a session produces: its working files, attachments, outputs, scratch space and logs.

Since 0.27.0 every new session gets one folder, the session storage envelope, named <session-name>-<stable-hash>. Netclaw records the folder’s absolute path in the database when the session first starts. When the session opens again, the daemon maps that path onto the current data directory, so a moved or restored home keeps working.

sessions/<session-name>-<stable-hash>/
├── workspace/
│ └── tool-calls/
├── attachment-staging/
├── artifacts/
├── worktrees/
├── logs/
│ └── session.log
└── subagents/
└── <run-id>/
├── task.md
├── result.md
├── artifacts/
└── logs/
└── session.log

Netclaw creates each directory the first time something needs it, so most sessions show only a few of them. A session that never wrote a file has just logs/.

FolderWhat it’s for
workspace/The session workspace and the base for relative file paths. A new session’s default working directory. Netclaw creates it the first time a shell call or a saved tool result needs it, and refuses to if the folder or the session folder above it is a link
workspace/tool-calls/The full output of a tool call that was too big to keep in the conversation, one <SHA-256 of the call id>.log file per call. The model gets the last part of the output inline (the last 12,000 characters, or 2,000 for shell_execute) and reads the rest with tool_output_read. If the file can’t be written, the truncation note says the output wasn’t kept
attachment-staging/Untrusted bytes from an inbound attachment, before the content scanner admits them. Accepted files move to workspace/inbox/
artifacts/Outputs the session, or you, should keep, such as files it attaches to a reply
Temp folderScratch space for the session’s own commands. Netclaw sets TMPDIR, TMP and TEMP to it for every process it launches, and it’s safe to lose. On Linux and macOS it lives outside the data directory, in /tmp/netclaw-<uid>/<key>/p (/private/tmp/... on macOS), where <key> is the first 16 hex characters of the SHA-256 of the session folder’s path and a child run uses .../<key>/c<8 hex>. Netclaw creates the folders with mode 0700 and refuses a shell launch or file write when the owner, the mode or a link is wrong. On Windows it stays inside the session folder, in tmp/parent/ and subagents/<run-id>/tmp/
worktrees/The preferred place for git worktree add. After Git creates one, the agent points the session at it with set_working_directory
logs/session.logThe raw activity log of the parent run
subagents/<run-id>/The same layout for each child run, kept under the parent so one folder holds a whole session. task.md holds what the parent asked and result.md what the child returned, which the parent reads with file_read. A child reply cut off at its output limit leaves the full text in artifacts/truncated-output.md, and result.md names it

Being inside the envelope doesn’t grant access. Audience restrictions, file-operation permissions, shell approval, protected-file rules and attachment validation all apply to these folders as they do anywhere else. See Security model.

Sessions that started before 0.27.0 have no binding. They keep the workspace and log paths they always had, for example logs/sessions/<session-id>/session.log. Netclaw doesn’t move, rename or migrate their files, and an upgrade doesn’t change where an old session resumes. A restart or a config change doesn’t change the layout of an existing session either.

To check after an upgrade, resume an old session and confirm its LogPath in netclaw sessions --once --json is unchanged, then start a new one and see that its path is under sessions/.

I wantDo this
A session’s logRun netclaw sessions --once --json and read LogPath
A subagent’s logUse the exact LogPath the spawn_agent result returns. Don’t search the logs folder
A file a session keptLook in that session’s artifacts/
To clear scratch spaceDelete the temp folder, /tmp/netclaw-<uid>/ on Linux and macOS. Nothing depends on it. On Windows, delete tmp/ in the session folder

The database stores each session’s folder as an absolute path, but the daemon re-roots it. If you restore a backup to a different location, such as from Docker’s /home/netclaw/.netclaw to /home/you/.netclaw, a session opens in sessions/<name>-<hash> under the new home and the daemon logs one warning naming the old and new path. Back up, restore and move netclaw has the tested walkthrough, and the one thing it needs on top.

A binary older than 0.27.0 doesn’t know about storage bindings. It resumes a session by its old rules, so its files end up in a different place than the 0.27 envelope, and it can’t replay some events a newer daemon wrote. Don’t downgrade a data directory that has run 0.27 sessions. See Upgrade netclaw.

FileWritten byHolds
logs/daemon-YYYY-MM-DD.logThe daemonOne file per UTC day, appended to. At 10 MiB the daemon starts daemon-YYYY-MM-DD.1.log, then .2.log, and so on, and the next UTC day starts over. Level Information by default. Change it with Logging:LogLevel:Default. Deleted after 14 days
logs/crash-YYYYMMDD-HHMMSS.logThe daemonA fatal startup or runtime exception. netclaw doctor reports recent ones. Deleted after 14 days
logs/signalr-<id>.lognetclaw chat -pThe transcript of a headless run
logs/sessions/<session-id>/session.logThe daemonThe raw log of a session that started before 0.27.0
sessions/<name>-<hash>/logs/session.logThe daemonThe raw log of a newer session. Subagent logs sit under subagents/

The daemon deletes daemon-*.log files, numbered segments included, and crash-*.log files older than Retention:Logs:Days (default 14), about 30 seconds after it starts and then every 12 hours. The date comes from the file name, the newest three of each kind always stay, and 0 keeps everything. Nothing else is touched: signalr-*.log, everything under logs/sessions/ and every session folder under sessions/ stay until you delete them. Data retention explains the setting. Releases before 0.28.0 delete nothing, so prune those files yourself. Under systemd, journalctl --user -u netclaw shows only start and stop lines unless you set NETCLAW_Logging__Console__Enabled=true, which also makes docker logs show the daemon’s output.

Background shell jobs write to jobs/<id>/output.log, rotating once to output.1.log at about 5 MB. The agent gets the exact path in the job result.