How to use it

Three steps to knowing exactly what leaves your machine.

1 Read the destinations. There is one row per place.

Open the Privacy page and read each destination.

Each row names what is sent, to whom, and whether it is on right now.

Privacy Language model only with a provider chosen Web search off out of the box Update check GitHub, at startup Every row says what is sent, to whom, and whether it is on right now.

2 Turn off anything you do not want.

Turn off Let D47 search the web and Check for updates at startup, and set the model to none.

Nothing leaves the machine.

Privacy Let D47 search the web off Check for updates at startup on With the model set to none and these off, nothing leaves this machine at all.

3 Check what it actually did.

Say "what have you sent anywhere".

The Log File reading lists each request with its destination.

what have you sent anywhere Ask The Log File reading logs every request, with the destination. Nothing is summarised for you — the log is the evidence.

! The one that stops people.

Speak as normal; there is nothing to set for the microphone.

Whisper transcribes your speech on this machine, and the audio never leaves it.

Your microphone is not a destination. Speech is transcribed on this machine by Whisper. The audio never leaves it, whatever the model setting is.

Exactly what Directive 47 sends off this machine, to whom, and whether it is sending it right now.

Ask for it

“what are you sending” “what leaves this machine”

What you get

2 of 4 destinations are active right now.

Language model → Anthropic
  Anthropic is selected. Your question, D47's reply so far, the guardrails, the persona and your backstory text, and the game state D47 assembled from your journal — system, body, station and docking state — are sent on every turn the model answers. Journal files themselves are never uploaded.

Update check → api.github.com, and github.com if you accept an update
  One request for the latest release tag at startup. Nothing about you goes with it — no key, no journal content, and no identifier beyond the request itself. Accepting an offered update downloads that release from github.com and replaces D47 with it; nothing is downloaded unless you ask for it.

Diagnostics and logs → nothing sent
  Logs are written beside the executable and are not uploaded.

Journal files → nothing sent
  Your journal is read from disk and never uploaded. Facts drawn from it — system, body, station — can reach the model as game state when one is configured; see the language model row.

The answer is computed from your settings as they stand at that moment. It is not a description of what Directive 47 could do in general, and it cannot go stale the way a page like this one can — which is why the answer is worth more than the page.

The destinations

Language model — the only one that receives anything from your gameplay. What goes: your question, the conversation so far, the guardrails, the persona, your backstory text, and the game state assembled from your journal. The lines D47 says in character without being asked — ambient remarks, the greeting, a core’s first words — carry your character sheet too, and about one ambient remark in four carries your backstory; the carrier’s captain and tower get neither. With personality on, the NPC lines Elite itself wrote go too, to be said in other words — a pirate’s threat, a station’s docking notice; a message another player typed never does. What does not: journal files, your key, or anything about your machine. Inactive when the provider is none, and also when a provider that needs a key is chosen and has none stored — selected-but-inert sends nothing.

And inactive when the endpoint is on this machine. If you have pointed the OpenAI-compatible provider at a loopback address, this row says that nothing leaves the machine at all and names the address so you can check it. That is the first time the accurate answer to what is leaving has been nothing — and it is a property of that address in these settings right now, not a promise about Directive 47. The judgement is deliberately literal: the address is read, never resolved, so a hostname that happens to point at your machine today is treated as remote and disclosed in full. Being wrong in that direction is the only safe way to be wrong here.

Web search — the same host as the language model, doing something different. When the web search row is on and a question needs current information, the language-model endpoint runs the search and reads the pages — your provider, or xAI when the endpoint is https://api.x.ai/v1, in which case the row names api.x.ai; Directive 47 only ever sees the reply. It is listed separately even though it adds no new address, because “your provider gets your question” and “your provider will go and fetch pages about it” are not the same disclosure, and organising this list by host rather than by what is done would have hidden the second behind the first. Off by default, and inactive whenever no model is usable — and inactive on an endpoint that offers no search, which a custom endpoint generally is. Until v0.26.1 that last case read as active and went on to describe pages being fetched and a penny being billed, none of which could happen there. Claiming a transfer that cannot occur is the safe direction to be wrong in and is still wrong: a disclosure is only worth reading if it describes this machine, these settings, right now.

Screen pictures — the language-model endpoint again. When the look at the screen row is on and you ask about something on screen, one JPEG of Elite’s window, or of the headset’s left eye while Elite is running in VR, goes to your provider with that question. Anything on screen goes with it, including comms, other Commanders’ names and Directive 47’s own panel. It is never saved, and a later turn does not send it again. Off by default. Inactive when no model is usable or the model in use does not read pictures, and the picture does not leave this machine when the endpoint is a loopback address.

BGS tick — tick.infomancer.uk, every ten minutes while Elite runs, for the time of the last background simulation tick. Nothing about you goes with it: no key, no Commander name, no position and nothing from your journal. It is reached over plain HTTP, because the host answers on nothing else, so anyone on the network path can see that d47 asked and could change the time that comes back; d47 keeps only that time, and only when it falls in a plausible window. BGS tick time under Outside sources in Settings (Galaxy search) turns it on; it is off by default.

GalNet news — cms.zaonce.net, Frontier’s GalNet server, for the newest articles at startup and every hour while d47 runs, and for up to two years of older articles the first time. Nothing about you goes with it: no key, no Commander name and nothing from your journal. The articles are kept in data\galnet.json on this PC. GalNet news under Outside sources in Settings (Galaxy search) turns it on; it is off by default. With it off, nothing is requested and articles already kept stay on this PC.

Server status — ed-server-status.orerve.net, Frontier’s server status page, once when d47 starts and then every ten minutes while the servers are up and every minute while they are not, whether or not Elite is running. Nothing about you goes with it: no key, no Commander name and nothing from your journal. Server status under Outside sources in Settings (Galaxy search) turns it on; it is off by default. With it off, nothing is requested.

Signal index — github.com, which redirects to GitHub’s asset storage, from the signals-1 release. When you search for a signal and the copy in data\signals is missing or more than 20 hours old, D47 downloads the daily index of signals Commanders have uploaded to EDDN: one file, several megabytes. A download that fails is tried again on a later search, no sooner than an hour after. Nothing about you goes with it: no position, no key, no Commander name, no identifier and nothing from your journal, and the search itself happens on this machine. Signal index under Outside sources in Settings (Galaxy search) turns it on; it is off by default. With it off, a signal search answers from your own scans alone.

EDDN — eddn.edcd.io. When you open a station’s commodity market, D47 sends its prices, with the station, its system, the game’s version and a random number made on this PC for your Commander. Opening its outfitting or shipyard sends the names of the modules and ships it sells. The signals and body counts your scanner finds go too, as do codex discoveries, settlements you approach, nav beacon scans and routes you plot; a route is where you intend to go. Your Commander name, Frontier ID, credits, cargo and ship do not go, and nothing from journals read before D47 started is sent. Share with EDDN under Sharing in Settings (Galaxy search) turns it on; it is off by default, and the model cannot turn it on.

Update check — api.github.com once at startup, for the latest release tag. Pressing Update now adds one more transfer: the build itself, from GitHub’s release downloads, which redirect to their asset storage — so the bytes arrive from objects.githubusercontent.com. That is a download rather than an upload, nothing about you goes with it, and it only happens when you press the button. Directive 47 refuses any URL that is not an asset on a release of this repository.

The download is checked against the d47.zip.sha256 published beside it, and deleted rather than unpacked if it does not match. That catches a truncated transfer or a mirror serving something else. It is not a signature: the hash and the bytes come from the same server, so it cannot detect a compromised GitHub. The same caveat applies to the speech models.

Model updates — raw.githubusercontent.com, once at startup and every 24 hours, for the published list of models, their defaults and their prices. Nothing about you goes with it: no key, no journal content and no identifier beyond the request itself. Fetch model updates in the Language model settings turns it off.

Stock stories — github.com, which redirects to GitHub’s asset storage, from the stories-1 release. D47 asks for the list of stock stories and the cast pictures it shows the first time the Stories page opens in a session, and for a story’s hidden layer and every cast picture when you pick it, and keeps them in data\stories. Nothing about you goes with it: no key, no Commander name, no position and nothing from your journal. Download stock stories in the Stories settings turns it off, and the Stories page then lists only stories already on disk.

Chatterbox voices — github.com, which redirects to GitHub’s asset storage, from the chatterbox-voices-1 release. Twelve Chatterbox voices come with D47. Any other is asked for the first time you pick it, press Play on it, or a line is due in it: one request for that one clip, naming the voice’s id and nothing else. The clip is kept in data\voices\chatterbox and used only while its size and SHA-256 match the list that came with D47. Active while Chatterbox speaks for any slot or story character.

Story ratings — d47-ratings.dseelinger.workers.dev. D47 asks for every stock story’s average rating the first time the Stories page opens in a session, and sends a vote when you rate a story you have picked or take your rating back. A vote carries the story, your stars and a random number made on this PC for your Commander, which is not your donation identifier. Nothing else goes with it: no Frontier ID, no Commander name, no key, no position and nothing from your journal. Story ratings in the Stories settings turns it off, and nothing is then fetched or sent.

Usage counts {#usage-counts} — d47-usage.dseelinger.workers.dev. One report a day, sent the first time D47 runs after the day ends in UTC. When the last send was not accepted, the start of D47 also sends today’s counts so far, and the rest of the day goes after the day ends: for each tool used that day, its name, whether you or the language model asked for it, and how many times. Nothing else goes with it: no identifier of any kind, nothing you said, no Frontier ID, no Commander name, no key, no position and nothing from your journal. The counts not yet sent are in data\usage-counts.json. Usage counts in the Privacy and egress settings turns it off, and the counts not yet sent are then deleted.

Speech recognition — silent while the hearing provider is This computer. With Groq, OpenAI, Deepgram or ElevenLabs selected, api.groq.com, api.openai.com, api.deepgram.com or api.elevenlabs.io receives the audio of every utterance Directive 47 transcribes, your API key, and the names from your journal used to recognise proper nouns. Hands free, that is every stretch judged to be speech, addressed to Directive 47 or not. No journal files, game state or other keys go with it.

Diagnostics and logs — never active. Logs are written to data/logs/ beside the executable and are not uploaded.

Journal files — never active. Journals are read from disk and never uploaded. Facts drawn from them can reach the model as game state, which is disclosed under the language model above rather than twice.

A voice that is not a destination either

Since Phase 59 there is a speech provider that sends nothing: Kokoro runs on this computer. Its model is downloaded once from huggingface.co — which is a destination, and is listed as one for as long as a download is happening — and after that the voice needs no network at all.

That is the whole reason it exists. Every other provider, free ones included, receives the text Directive 47 speaks, and that includes re-voiced in-game messages written by other players. With Kokoro selected for those slots, nobody’s words leave your machine to be spoken.

Shared excerpts and journal histories — the newest destination, and the one that reverses a sentence Directive 47 used to say about itself. Donation shipped with nowhere to send: an excerpt was copied and pasted by a human, and a comment in the code said there is no backend and there is not going to be one. There is one now, argued in #175, because the requirement changed underneath that sentence — a donated journal history is 32.5 MB compressed followed by about 85 KB a day, and no manual route carries that or can be reached by a stranger.

It is not like usage counts either. Directive 47 sends one thing without being asked: once a day (or, after a send that was not accepted, a part day at startup), how many times each tool was used, with no identifier and nothing from your journal (Usage counts). It is on by default and Usage counts in Privacy settings turns it off. A donation is different in kind: it sends nothing at all until you have read a full description of it and pressed a button, every time — no standing consent, nothing remembered, no automatic upload — and the row above says so.

The press is the switch. The address ships in the build — Directive 47’s own store, named in full by the disclosure row — and the send buttons are simply there. What was never true and still is not: nothing uploads on its own. Every send is one deliberate press over a payload or a report you just read, no standing consent, nothing remembered. It read differently until 2026-08-31, when the paste-an-address row was retired: the address was the switch only because the row asked every installation for a URL only the project knew.

What is stored, and for how long. An incident excerpt is deleted 30 days after it arrives, by a rule on the store rather than by anybody remembering to. It may well go sooner — there is no reason to keep one past the defect it was cut for — but that is somebody deleting it and not a rule, so the thirty days is what is promised. A donated journal history is kept indefinitely, on purpose: it is a regression case, and one that expires stops being one. Either goes on request, and either is a single delete.

Directive 47 keeps its own copy of what it sent. In data\donations, beside the executable: the exact bytes, and their hash. While a human was the transport, what is shown is what leaves was something you could see; an upload turns it into a claim about code, and the receipt turns it back into something you can test with certutil -hashfile. It is also what a deletion request quotes.

Your donations are grouped, and that is a reversal too

Directive 47 used to say that two donations from the same Commander could not be joined. That was true, and it is not any more.

A journal history you add to has to be recognisable as the same history, or it is not an accumulation — it is a pile of unrelated blobs. So a send carries a random number identifying this installation: made on this machine the first time you donate and never before, not derived from your Commander name, your Frontier ID or anything about your computer, and used for donations and nothing else. The stand-in names inside a donation are unchanged — still per-donation, still by field list.

The claim is now weaker and still worth stating: donations from one installation accumulate under a random token that identifies an install, not a person. You read it here, and in the Help improve D47 page, before the first send rather than after (#176).

Withdrawing is one press, and it is no harder than consenting was. Forget it, and delete what was sent asks the store to delete every donation ever made under this installation’s identifier, then forgets the identifier here and writes a record of what went into data\donations. You do not have to post anywhere or ask anybody, which is the point: a withdrawal that is harder than the consent was is a defect in the consent (#167).

If the store cannot be reached, the identifier is kept and the row says so — it is the only handle anyone has on what was sent, so losing it would strand the data rather than delete it. Press again when the connection is back.

What is not deleted is what was decided because of it. A defect a donation found stays fixed, the release that carried the fix stays released, and the changelog line naming it stays written. Those are the product of having read the data once; they are not the data, and a published release never moves. Neither is anything you copied or saved yourself and took somewhere else — anything posted publicly can be archived beyond anyone’s reach.

Two things are accepted rather than solved, and both are said here rather than discovered. A thirteen-month history is easier to re-identify than a ten-minute excerpt — more surface, more distinctive routes, more chance one rare system pins the set to a person — and pseudonymised was never anonymous. And a second PC, a fresh install with no restore, or a cleared data\ folder starts a second pile under a new number, with nothing saying the two halves are one history. The only fix for that would be a token derived from your machine, which is the identifier this whole design refuses.

Your microphone is not a destination, unless you make it one

It is worth saying plainly, because Phase 13 added hands-free listening and “the microphone is open all the time” is a sentence that deserves an answer rather than a shrug.

Out of the box, audio does not leave this machine. Speech becomes words through a model running on your own computer. The one row that changes that is the hearing provider: choose Groq, OpenAI, Deepgram or ElevenLabs and the audio of every utterance goes to it, disclosed under Speech recognition above. Audio is not written to disk either way — it lives in a half-second ring buffer and is overwritten.

What the hands-free settings change is what gets kept for long enough to transcribe. In push-to-talk that is only what you held the key for; in the two hands-free settings it is every stretch of speech in the room, and in wake-word mode the ones that were not addressed to Directive 47 are discarded without reaching the transcript, the panel or the log. Both are off out of the box, the row that turns them on is unreachable by the model, and the panel shows the microphone’s state the whole time it is open — on the desktop and in the headset.

With the local model, the one thing that crosses the network for listening is the speech model file itself, fetched once from huggingface.co. It is listed on the settings surface for as long as a model is selected and the hearing provider is this computer.

Settings

Check for updates at startup

One request to api.github.com at startup. Off means Directive 47 makes no network call of its own, and offers no update to install.

“stop checking for updates” / “turn off update checks” “start checking for updates” / “turn on update checks”

The whole sentence has to be the phrase rather than merely contain it. This is the one spoken route that changes a setting, so a sentence that only mentions it gets an answer, not a change.

The model cannot reach this row. It decides whether anything leaves at all, and a model that could switch that back on is a model that could be told to by text it read in an in-game message.

Where donations are sent

The address ships in the build: Directive 47’s own store, behind a Cloudflare Worker that is the only thing able to write to the bucket — there is no storage credential anywhere in Directive 47, and the disclosure row above names the address in full. There used to be a settings row here to paste an address into, and it is gone on the project’s own ruling (2026-08-31): it asked every installation for the one URL only the project knew, and the switch it doubled as was never the real guard. The real guard is unchanged — nothing is sent until you press, every time, and the address travels over https only.

Because the address is compiled in rather than stored, there is nothing here for the model — or anything else — to redirect: changing where a donation goes now means changing the code.

What Directive 47 remembers about you

A read-only summary of the memory store — how many facts are kept, and how many of them you told it yourself — with one button that empties the file.

It empties every Commander in the file, not just the one currently aboard. “Forget me” is not “forget the character I happen to be logged in as”, and a privacy control that left three other characters’ facts on disk would be one that reads as a control and is not.

The button is here rather than in the memory section because this is where you would look for it. There is no spoken phrase for it and no tool that can call it — “forget everything about me” is a sentence a transcriber can produce out of a misheard one, and this is the one action in that feature that cannot be undone.

The disclosure rows

The settings panel carries one row per destination, saying the same things this page does {#egress-recap} {#egress-websearch} {#egress-screen} {#egress-updates} {#egress-modelcatalog} {#egress-diagnostics} {#egress-journal} {#egress-tts} {#egress-stt} {#egress-galaxy} {#egress-colonisationplanner} {#egress-colonisationprogress} {#egress-bgstick} {#egress-galnet} {#egress-serverstatus} {#egress-signalindex} {#egress-eddn} {#egress-models} {#egress-chatterboxvoices} {#egress-notableplaces} {#egress-communitybiology} {#egress-hullart} {#egress-codexpictures} {#egress-codexpublish} {#egress-avatarclips} {#egress-stockstories} {#egress-storyratings} {#egress-usagecounts} {#egress-pictures} {#egress-codexcaptures} {#egress-ownvoice} {#egress-customvoices} {#egress-captainslog} {#egress-screenshots} {#egress-donation} — but computed live from your settings rather than written down once. They are read-only: not something you set, something Directive 47 says, sitting next to the settings that change it.

The tool surface, for contributors

get_data_egress

Lists every destination, whether it is active under the current settings, and what is sent there. Takes no arguments.

{"type":"object","properties":{},"required":[],"additionalProperties":false}

The panel’s disclosure rows and this tool read one list, so neither can drift from the other.