Data & security
Jimothy is local-first: there is no Jimothy server or account. Configuration, runs and logs are plain JSON / JSONL files on your machine; agents run as processes under your user.
Data folder
Section titled “Data folder”By default Jimothy stores everything in a factory folder inside Electron’s per-app userData directory:
| OS | Default data folder |
|---|---|
| macOS | ~/Library/Application Support/Jimothy/factory |
| Linux | ~/.config/Jimothy/factory (or $XDG_CONFIG_HOME/Jimothy/factory) |
The exact path is shown at the top of Settings (Data stored in …). Set FACTORY_DATA_DIR before launching to use another folder.
File layout
Section titled “File layout”factory/├── settings.json Settings (plain text, including Settings → Environment variables)├── projects.json Projects├── pipelines.json Pipelines├── connections.json Accounts (tokens encrypted)├── triggers.json Triggers (webhook secrets encrypted)├── trigger-state.json Per-trigger dedup memory, last poll, last error, run counts├── harnesses.json Your edits to built-in harnesses and custom harnesses (API keys encrypted)├── channels.json Notification channels (URLs and tokens encrypted)├── inbox.json Inbox (newest 300 items)├── meta.json Run counter├── remote.json Remote-access token (encrypted)├── runs/│ └── run_<id>/│ ├── run.json The run: status, steps, outputs, rendered prompts, cost, links,│ │ and a snapshot of the pipeline definition it ran│ ├── logs/│ │ ├── _run.jsonl Setup & run log│ │ └── <stepId>.<attempt>.jsonl One log per step attempt│ └── tmp/ Prompt files for harnesses that read the prompt from a file├── workspaces/ Default Workspaces folder: run-<number>-<issue-slug>/ per run└── tmp/ Short-lived folders for "Build with AI" pipeline generationEach log line is a JSON object: {"ts": "<ISO time>", "kind": "assistant", "text": "…"}, with kind one of stdout, stderr, system, assistant, thinking, tool, tool_result, result, error.
Notes:
- Config files are written atomically (temp file + rename) and debounced; everything is flushed when the app quits.
- Runs load from
runs/*/run.jsonat startup. The app lists the latest 300 in its live state; older runs stay on disk. - Delete run removes
runs/<id>/. The workspace is never deleted by that; see Delete a run’s workspace after it succeeds in Settings. - To back up Jimothy, back up the data folder. Restoring it on another machine or user account restores everything except encrypted secrets (see below).
Secrets and encryption
Section titled “Secrets and encryption”These fields are encrypted at rest:
| File | Encrypted fields |
|---|---|
connections.json |
Jira API token, Linear API key, GitHub token |
triggers.json |
Webhook secret |
harnesses.json |
API key |
channels.json |
URL (Slack/Discord/Teams webhook URLs are secrets), bearer token |
remote.json |
Remote-access token |
Encryption uses Electron’s safeStorage, which is backed by the OS keychain: Keychain on macOS and the Secret Service (libsecret / KWallet) on Linux. Encrypted values are stored as enc:v1:<base64>.
Things to know:
- Secrets don’t move between machines. They’re tied to the OS keychain of the machine and user that wrote them. Copying the data folder elsewhere keeps your pipelines and runs, but accounts, API keys and channel URLs need to be entered again (values that can’t be decrypted load as empty).
- If the OS offers no encryption (for example a Linux session without a keyring), Jimothy stores the value unencrypted with a
plain:marker rather than failing. On Linux, install and unlock a Secret Service provider (the packaged builds depend onlibsecret). - Not encrypted:
settings.json(including Settings → Environment variables), pipeline and project variables and environment, step environment, and everything in runs and logs. Don’t paste secrets into prompts, and prefer a harness’s API key field or an account over plain environment variables where possible. - Agents see what you give them: environment variables are inherited by every step’s process.
Security model
Section titled “Security model”Agents run as you. CLI harnesses run with your user’s permissions, and most are configured for unattended operation (--dangerously-skip-permissions, --full-auto, --yolo, --force, --allow-all-tools, --yes-always, --dangerously-allow-all). An agent can read and modify anything your user can.
Issue text is agent input. Anyone who can create or edit an issue that matches a trigger can put instructions into your agents’ prompts (prompt injection). So:
- only point triggers at trackers and projects where you trust who can create or label issues;
- use a hand-off label, state or assignee that only trusted people set;
- prefer Git worktree workspaces, which isolate each run on its own branch, over Existing folder;
- put a human approval step before anything that pushes, opens PRs against protected branches, or deploys;
- give the credentials used in steps (
GH_TOKEN, cloud keys) the least privilege that works.
Shell steps quote template values automatically, so issue text interpolated into a command can’t inject shell syntax unless you opt out with | raw. See Template variables.
The webhook server binds to 127.0.0.1 by default, verifies Linear and GitHub HMAC signatures, and checks a shared token for other webhook triggers. Set a secret on every trigger you expose through a tunnel. See Webhooks.
Remote access is tailnet-only. The remote server listens on loopback (or the Tailscale interface in HTTP fallback), is published with tailscale serve, refuses to run if Tailscale Funnel is enabled on its port, and requires an access token. See Remote access.
Claude Code and root. Claude Code refuses --dangerously-skip-permissions as root. Run Jimothy as a normal user, or edit the harness to use --permission-mode acceptEdits. See Claude Code.
Network access. Jimothy itself talks only to the services you configure: your trackers’ APIs, LLM APIs you set up as harnesses, notification webhooks, and tailscale. The agents you run make their own network calls.