How to use it
Two steps to looking something up in the galaxy.
1 Turn web access on. It is off out of the box.
2 Ask.
! The one that stops people.
Why it works this way
Looking things up in the galaxy — the first thing D47 does that needs the internet.
1 Off until you turn it on.
2 What actually leaves, when it is on.
3 The other one runs the other way.
You never have to take this page's word for any of it. The Privacy report works the same list out from your actual settings rather than repeating it here, so a page going stale cannot make it wrong.
The details
Look up star systems, and work out how far apart two of them are.
“how far is Colonia” “find a high tech system within 30 light years” “what’s the nearest Federation system”
This is the first thing d47 does that needs the internet. It asks spansh.co.uk, which indexes the galaxy from data Commanders share — and, for one commodity’s prices, Ardent Insight, which applies the same Commanders’ reports as each one arrives. Both are behind the one setting below, and it is off until you turn it on.
Look things up in the galaxy
The one setting. Off by default.
When it is off, asking about a system gets you “Galaxy search is switched off, so I can’t look that up” — a capability that is off, not an error, so the conversation carries on. When it is on, two things leave this machine:
- the system name you asked about, and any filters — an allegiance, a distance, an economy
- where you are, whenever the question is relative to you, because “the nearest high tech system” cannot be asked without saying where from
No key, no identifier, nothing else from your journal. The Privacy section computes this same list rather than repeating it by hand, so it cannot go stale.
Turning it on takes effect immediately. There is no restart.
Notable places for adventures
A second setting, added with list.md Phase 47 and off by default, and a second host. When the ship’s AI writes you an adventure it may pick the story’s stops from the Galactic Exploration Catalog on edastro.com — the community catalogue of nebulae, notable bodies, wrecks, memorials and tourist sites that the Galactic Mapping Project was migrated into. One request fetches the whole catalogue, about two megabytes, and the choosing by distance happens on this machine: where you are never leaves it, and nothing about you goes with the request. The catalogue is kept in memory for a few hours so a draft and its revisions do not fetch it three times, and it is never written to disk.
A lookup and never a copy. Nothing from the catalogue is written into d47’s own tables; the
catalogue’s one-line descriptions reach the model labelled as third-party information, and every
place it suggests is still checked against spansh’s id for the system before a story can be
offered — two sources, and a disagreement refuses the place. Its content is CC BY-NC-SA 3.0,
acknowledged in NOTICE; d47 is non-commercial.
With this off, a generated adventure still works, choosing its stops from the galaxy search and the model’s own knowledge. With galaxy search off, no adventure can be generated at all, because the places in a story have to be real and this is the thing that checks.
Why the filters are checked here rather than there
The search service ignores filter keys it does not recognise. It does not reject them or warn about them. Measured against the live service on 2026-08-14, within 20 light years of Sol:
| Request | Result |
|---|---|
allegiance: ["Federation"] |
60 systems |
allegience: ["Federation"] (misspelled) |
108 systems |
not_a_real_filter: ["Federation"] |
108 systems |
| no allegiance filter at all | 108 systems |
The misspelled row is the dangerous one. Nothing fails, nothing warns, and the answer that comes back is a perfectly good answer to a question nobody asked — you asked for Federation systems and got every system, presented as though the filter had applied.
So d47 keeps its own closed list of filters and refuses one it does not know before building a request. If you ask for something that is not on the list, you get told what is, rather than a confident wrong answer. This is the first guardrail — never invent game data — applied to a service that will let you invent it without complaint.
The filters are distance, allegiance, government, primary_economy, security and state.
Ranges take one number for an upper bound (30 means within 30) or two separated by a dash
(10-50).
The list was one filter longer until 2026-08-16, and that one was doing nothing
There was a population filter here, from Phase 14 until the colonisation work went looking for
exactly that field and measured it. Within 15 light years of Sol, where 48 of the 51 systems are
populated:
| Request | Systems returned |
|---|---|
| no filter at all | 51 |
| a key the service has never heard of | 51 |
population: {"min":"1","max":"1000000000000"} |
51 |
population: {"min":"0","max":"0"} |
51 |
| the same bounds as numbers rather than strings | 51 |
population: {"value":["0"]} |
0 |
population: {"value":["19160"]}, a population a system in range has |
0 |
The field is real — the service publishes a minimum and a maximum for it — and only the range shape is dropped. So every “find me a system with a million people” this ever answered was the whole neighbourhood with a population filter written on the front of it: the precise failure the section above describes, shipped inside the class built to prevent it. A filter the service ignores must not be offered, so it is gone. The number itself is on every result, which is how colonisation tells an unpopulated system from a populated one.
A worse trap than the misspelling: a real filter that matches nothing
state is not sent under the name state, and finding that out cost a measurement rather than a
guess. There is a field called state. It has its own published value list carrying exactly the
twenty-one words this filter accepts, and it is honoured rather than dropped. It also matches
nothing — zero systems for every value, including None, where a bogus key returns the unfiltered
count. No result row carries a state field at all.
| Request, within 200 light years of Sol | Result |
|---|---|
| no state filter | 10,000 (the cap) |
state: ["Boom"] |
0 |
state: ["None"] |
0 |
controlling_minor_faction_state: ["Boom"] |
1,286 |
controlling_minor_faction_state: ["Outbreak"] |
68 |
Measured 2026-08-15. This fails as an empty answer rather than a wrong one, which is worse than the misspelling above: “there are no systems in Boom near you” reads as a fact about the galaxy, and a Commander has no way to tell it from one. So d47 offers the short word and sends the long key.
The state itself is crowd-reported and turns over on the background simulation’s tick, so the answer says systems reported in Boom — the same framing the station stock carries.
What comes back
One system record from the service is 268 KB — every body, every station, every market. A search returning three systems is 44 KB. None of that reaches the model: d47 reads six fields per system and drops the rest, so the answer is a handful of facts that can be said out loud in a cockpit rather than a database dump billed by the token.
The station list is read for its length and then discarded. How many stations a system has is worth saying; which ones they are is the next question.
Results always say how many matched in total, not just how many were read out. “412 systems matched; here are the nearest 5” is a different answer from “there are 5”.
Where to buy it, and what it costs there
Where can I buy tritium? — and, the same question read backwards, where do I dump 700 tonnes of it?
How much you want is part of the question, not a detail. A station 40 light years further out that is 200 credits a tonne cheaper is the wrong answer for eight tonnes and the right one for seven hundred and eighty. Tell Directive 47 the tonnage and it ranks by what the whole load costs to go and get; leave it out and it ranks by price and tells you the distance.
Say the tonnage and stations that cannot fill the order drop out entirely. The cheapest steel in the bubble is not an answer if the station is holding nine tonnes of it.
Every price has a date on it, and this is the part to take seriously. Prices come from other Commanders docking and sharing what they saw. Supply ages fastest of all — a colonisation rush strips a station in hours — so an answer that sounded current would be worse than one that admits it is a month old:
Best for buying 700 tonnes of Tritium within 50 ly of Sol: Jameson Memorial (Shinrarta Dezhra),
14.5 ly, 42,050 cr a tonne, 12,400 in stock, 29,435,000 cr for the load — reported 6 hours ago.
A market you stood in yourself is labelled as yours, because it is the one figure with no caveat. Stations dropped for quoting prices too old to trust are counted rather than silently skipped — “nothing within fifty light years” and “eleven stations, all quoting last month” are different answers, and only one of them means you should look further out.
Fleet carriers are left out unless you ask for one. Their prices are set by their owner and can be a joke, and the carrier may be a hundred light years away by the time you arrive.
The radius answered is the radius searched
The search asks for the commodity by name. It fetches a fixed number of the nearest markets — 150 — and near a busy system those 150 are only a few light years across. So it narrows the request to stations that actually hold stock of the thing you asked about, and spends the whole 150 on those.
That is there because of what happened without it. Asked for the closest place to buy 200 Landmines near Eurybia, Directive 47 said there was none within 250 light years — twice, with rising confidence — while its own data source had 5,229 units eleven light years away. The 150 nearest markets to Eurybia carried none, and “none of the ones I looked at” had been reported as “none in the radius”.
And where it still runs short, it says so. If the 150 run out before the radius does, a negative answer names the distance actually reached rather than the one you asked about:
Nothing in the 150 markets I could check is buying Land Mines in 200 tonne lots. Those reach
14.2 light years of the 250 you asked about, so there is more out there I have not looked at.
Nothing extra is fetched for any of this. The trade route planner already pulls whole markets for everything in range and already caches them, so asking about two commodities in one evening costs one lookup, and the ranking runs here on your own machine.
When it cannot answer
Everything that can go wrong becomes a sentence rather than an error: the service being unreachable, rate limiting you, taking too long, or having no record of the system you named. A system the service does not know produces “I couldn’t find one of those systems”, not a failed turn.
Tools
search_systems
Find star systems matching some criteria, nearest first.
{"type":"object","properties":{"allegiance":{"type":"string","description":"Superpower allegiance.","enum":["Alliance","Empire","Federation","Guardian","Independent","Pilots Federation","Thargoid"]},"distance":{"type":"string","description":"How far to look, in light years."},"government":{"type":"string","description":"Form of government.","enum":["Anarchy","Communism","Confederacy","Cooperative","Corporate","Democracy","Dictatorship","Feudal","None","Patronage","Prison","Prison Colony","Theocracy"]},"limit":{"type":"integer","description":"How many to return, 1 to 20. Default 5."},"near":{"type":"string","description":"Measure from this system. Defaults to theirs."},"primary_economy":{"type":"string","description":"The system\u0027s main economy.","enum":["Agriculture","Colony","Extraction","High Tech","Industrial","Military","None","Refinery","Service","Terraforming","Tourism"]},"security":{"type":"string","description":"Security level.","enum":["Anarchy","High","Low","Medium"]},"state":{"type":"string","description":"What the controlling faction is going through. Crowd-reported, so this finds systems reported in that state.","enum":["Blight","Boom","Bust","Civil Liberty","Civil Unrest","Civil War","Drought","Election","Expansion","Famine","Infrastructure Failure","Investment","Lockdown","Natural Disaster","None","Outbreak","Pirate Attack","Public Holiday","Retreat","Terrorist Attack","War"]}},"required":[],"additionalProperties":false}
A search with no filters is refused rather than run — it would match the whole galaxy.
distance_between
The straight-line distance in light years between two star systems.
{"type":"object","properties":{"from":{"type":"string","description":"The system to measure from. Defaults to theirs."},"to":{"type":"string","description":"The system to measure to."}},"required":["to"],"additionalProperties":false}
The arithmetic is d47’s own. The service returns positions and d47 computes the distance from the coordinates, so “how far” has the same answer wherever it is asked from.
find_nearest_station
Where to buy a named module or ship, nearest first. A rare good is answered from a table instead, since it has one selling station and no other.
{"type":"object","properties":{"commodity":{"type":"string","description":"A commodity traded there, by name."},"include_carriers":{"type":"boolean","description":"Also fleet carriers, whose prices are player-set and can move."},"large_pad":{"type":"boolean","description":"Only stations with a large landing pad."},"limit":{"type":"integer","description":"How many to return, 1 to 20. Default 5."},"max_distance":{"type":"number","description":"How far to look, in light years. Default 50."},"max_price_age_hours":{"type":"integer","description":"How stale a quoted price may be, in hours. Default 720, one month."},"max_station_distance":{"type":"number","description":"Furthest from the star, in light seconds."},"min_supply":{"type":"integer","description":"Least in stock, or least demand when selling."},"module":{"type":"string","description":"A module to be sold there, by name \u2014 \u0022Frame Shift Drive\u0022."},"module_class":{"type":"string","description":"Module size, 0 to 8.","enum":["0","1","2","3","4","5","6","7","8"]},"module_rating":{"type":"string","description":"Module rating, A to I.","enum":["A","B","C","D","E","F","G","H","I"]},"near":{"type":"string","description":"Search out from this system. Defaults to theirs."},"order_by":{"type":"string","description":"Nearest first, or best price first. Default price.","enum":["distance","price"]},"selling":{"type":"boolean","description":"Sell it rather than buy it."},"ship":{"type":"string","description":"A ship to be sold there, by name \u2014 \u0022Krait MkII\u0022."},"surface_stations":{"type":"boolean","description":"Also planetary ports and settlements. Default false."},"tag":{"type":"string","description":"Internal. Leave unset."},"tonnes":{"type":"integer","description":"How many tonnes, if they said."}},"required":[],"additionalProperties":false}
A rare good is answered from its one station, not from a sweep (#118). Each of the 142 rares is sold at exactly one station, which is usually far outside any radius worth searching, so asking the index for markets near you returns nothing useful. The station and system come from the shipped table, which needs no web access and answers with the galaxy search setting off. How much is on offer per visit is the one thing the table cannot hold — it is set by that station’s economic state and can be far higher during a boom — so it is read as the market’s own last report and given with its age. Where there is no report, or no web access to ask for one, the station is still named and the quantity is said to be unknown. The ship’s hold is no part of the answer: what the station is offering is the ceiling on a visit, and it is nearly always the smaller of the two. Asking where to sell a rare is a different question, and the ordinary radius sweep still runs for it.
Commodity prices come from a second host (#350). Everything else on this page is spansh; asking where to buy or sell one named commodity goes to Ardent Insight instead, which applies each EDDN message as it arrives. Measured on 2026-09-06 from Ega during a Community Goal rush, spansh’s station index carried the same stations at market figures one to two hours older and, for three of them, weeks older — so d47’s own freshness rule, working exactly as written, threw away stations INARA was showing with a two-minute-old quote, and the nearest station d47 named was one that had already been emptied. Nothing about the answer changed: same tool, same knobs, same page, same sentence, and the search says nothing about which host it asked.
If Ardent cannot be reached the search fails and says so. There is deliberately no quiet fall-back to spansh’s figures, because an answer that might have come from either source is one you have no way to read.
A station the feed leaves out is not added back from your own visits
(#350). Your Market.json still beats the feed’s
figure for a station the feed did return, whenever yours is newer — that is the station under
your feet and the one exact price d47 holds. But a station missing from a whole reply is one the
feed is saying no about, since the commodity, the supply floor, the radius and the age bound all
went into the request, and putting it back made d47 name a market that had been emptied hours
earlier. Where a reply comes back cut short it can speak for nothing it left out, so there your
visits still fill the gap — and a station that comes back that way has to clear the same floor,
radius, pad and age as everything else. The sweep behind route planning and a build’s sourcing is
paged rather than complete, and still folds your visits in as it always did.
The four filters INARA’s commodity search has and this one lacked
(#296): max_station_distance in light seconds
from the star, min_supply as a floor a station must clear (demand when selling), surface_stations
to let planetary ports and settlements back in — they are out unless asked for, as INARA has it —
and order_by, which is price for the ranking this search has always had and distance for
nearest first. Only min_supply goes into the request, as the least a station must hold to be
answered for at all; the other three are applied here, off the arrival distance and station type
every result already carries. A station whose type or arrival distance the index does not know is
kept: unknown is not surface, and unknown is not far.
Nearest first changes what is said, not only the order. When the Commander orders by distance the nearest station is the answer, so the ear gets just enough of it to go — what was searched for, the winning station, its system, and the distance to it:
Nearest for buying Palladium, Platinum Reach (HR 6012), 53.3 ly. System is on your clipboard.
Price, stock, pad distance from the star and quote age used to be read out here too; they are still on the Routing tab table, along with the rest of the ranking, and reading all of it out was detail the ear paid for and could not act on (#325). The price ordering still reads every station out, as it always did, and still names each one’s distance from the star wherever the index knows it, because a pad 60,000 light seconds out is the half of “how far” the Commander feels after the jump.
The winning system goes on the clipboard unconditionally, the same way plot_course puts one
there, so a nearest-first search is also the fastest way to get a system name into the galaxy map.
Saying “set a course” afterwards plots to it without the Commander repeating the name, and
“set a course and take us out” does the same and then leaves the pad — see
flight controls for both. Neither phrase has
anywhere to route with nothing found yet.
The saved Community Goal search — the INARA query with every one of these baked in — lives on the community goals page, and runs through this tool.
Every knob the commodity half has is an argument (#157).
It used not to be. max_distance was clamped to 250 inside the handler, so “expand your search
out to 500 light years” became 250 with nothing said, and the staleness bound was not a parameter
at all, so “expand your staleness filter” had no road from the sentence to the search. Both read
as an assistant ignoring an instruction when it was the schema that could not say yes.
So there is no ceiling on max_distance now. What bounds the radius is what the source honours
and how far the search actually reaches — and it says how far it got in its own words, which
is the truthful version of the sentence the cap was inventing. The market index does hold a horizon
of its own, measured at about 500 light years on 2026-09-06, but d47 does not write that number
down: the number it reports is read off the reply, so ask for 2,000 light years and the answer names
the distance the markets it got back really covered rather than claiming the radius.
And where the index cuts the reply short, the answer says the reach is unknown. It sends at most a thousand markets to a question, offers no second page, and — measured 2026-09-06 — does not cut by distance: widening one already-full search from 250 to 500 light years dropped 556 markets that were inside 250, the nearest of them 43 light years out with stock in it. So the furthest market that arrived measures the cut rather than the search, no distance is claimed at all, and what a best-of out of a cut list may be missing is nearer stock rather than further — which the answer says outright.
max_price_age_hours and include_carriers were both decisions taken in the handler and are now
the Commander’s to change:
carriers are still out by default, because their prices are player-set and the station itself may
be a hundred light years away by the time anybody arrives, but a carrier is sometimes the only
seller and INARA’s equivalent search includes them.
Two rules ride along with that, and they are the reason the knobs are safe to expose.
A question that was changed is said back. A search that swept five hundred light years and one that swept fifty read identically otherwise, which leaves a Commander no way to hear that their instruction landed — so a non-default radius, price age or carrier setting is echoed: “Searched out to 500 ly, prices up to 60 days old.” An unqualified search says nothing and reads exactly as it did before this existed.
A refused widening names its knob and its ceiling. max_price_age_hours stops at 8,760 — a
year — and asking past it says so with the parameter’s own name attached rather than narrowing the
question in silence. “That’s as far as I search” is the sentence the change exists to delete.
And limit is under the same two rules (#178).
It was not, and it was worse than a clamp: a value outside 1 to 20 was reset to 5, so asking for
fifty returned five and the answer said nothing about either number. It now stops at 20 and starts
at 1, says so when it applies — “You asked for 50; limit stops at 20, so that is what I looked
for.” — and echoes a non-default count that was honoured, the way the radius is echoed. Both
halves of the tool obey it: the commodity search and the module-and-ship search take the same
argument and now owe the same sentence.
Module and ship names are not in the schema. There are 132 modules and 48 ships, and an
enum that large sits in prompt position 1 where one changed byte invalidates the whole cached
prefix — several kilobytes paid for on every turn to answer a question asked once a session. So
the parameter is free text and the name is matched against the real catalogue here, before a
request is built.
The matcher handles the two ways a spoken name arrives wrong. A fragment — “shield generator” for “Bi-Weave Shield Generator” — is what a Commander says. A misspelling — “Frame Shift Drve” — is what the transcriber does to them. Fragments are offered first.
This matters less than the system filters did and still matters. The service does honour a module name it has never heard of: it returns nothing. So a typo produces “nowhere within 100 light years sells that”, which is a false statement about the galaxy rather than a wrong filter. Catching it here turns it into “I don’t know a module called that; did you mean…”.
Stock is crowd-reported, so every result says when it was last seen. It is not what is there, it is what somebody last reported was there — and a live search on 2026-08-14 returned a carrier whose outfitting was last reported in October 2024 alongside two stations reported that morning. Reading the stale one out as current is how a Commander flies a long way for an empty shelf.
Getting a position out of a name takes one search: there is no lookup-by-name endpoint —
api/system/name/Colonia is a 404, and the by-id endpoint wants an id64 nobody says out loud —
so d47 names the system as a search reference and reads back the coordinates the service
resolved it to.
find_body
The nearest planets, moons and stars matching some criteria.
{"type":"object","properties":{"body_type":{"type":"string","description":"The kind of body, by name \u2014 \u0022Earth-like world\u0022, \u0022Class I gas giant\u0022."},"hotspot":{"type":"string","description":"A mining hotspot material in the body\u0027s rings \u2014 \u0022Painite\u0022, \u0022Void Opal\u0022."},"hotspot_count":{"type":"integer","description":"Exactly how many overlapping hotspots \u2014 not a minimum. A triple is 3."},"landable":{"type":"boolean","description":"Only bodies that can be landed on."},"limit":{"type":"integer","description":"How many to return, 1 to 20. Default 5."},"max_distance":{"type":"number","description":"How far to look, in light years. Default 50."},"near":{"type":"string","description":"Search out from this system. Defaults to theirs."},"reserve_level":{"type":"string","description":"How rich the rings are.","enum":["Common","Depleted","Low","Major","Pristine"]},"ring_type":{"type":"string","description":"Ring composition.","enum":["Icy","Metal Rich","Metallic","Rocky"]},"signal":{"type":"string","description":"A signal on the body\u0027s surface: \u0022Biological\u0022, \u0022Geological\u0022, \u0022Human\u0022, \u0022Guardian\u0022 or \u0022Thargoid\u0022."},"signal_count":{"type":"integer","description":"Exactly how many of that signal \u2014 not a minimum. Omit unless they asked for a number."},"terraformable":{"type":"boolean","description":"Only terraforming candidates, which are worth far more to map."}},"required":[],"additionalProperties":false}
One index answers three questions that sound unrelated:
- where the nearest Earth-like world is — or neutron star, or water world, for a jump or a payday
- where there is something on a surface — biological and geological signals, and how many
- which ring to mine — a hotspot material, how many overlap, the ring’s composition and how rich its reserves are
Body types are matched, not listed. There are 61 of them, so the same reasoning applies as for module names — and the matcher takes a unique fragment as well as a spelling: “earth-like” names exactly one subtype and is what a person says. “gas giant” names six, so it is refused with the candidates rather than answered about whichever one came first.
Two things about this search were measured and are worth knowing before changing it.
The signal filter has a third wire shape, different from both the system filters and the
station module group. It is {"name":{"value":["Biological"]},"count":2} — a choice member beside
a bare number. The obvious spelling, {"Biological":{"min":"1","max":"40"}}, is accepted and
ignored: within 20 light years of Sol it returned the unfiltered 1,315 bodies, exactly as a
misspelled key did.
A signal count is exact, not a minimum. Asking for 1 returned 41 bodies, 2 returned 14, 3 returned none and 4 returned 2 — not a decreasing series, and every result carried precisely the number asked for. So the schema says “exactly how many” rather than “at least”, because a “three or more” that silently meant “exactly three” would be a wrong answer that reads like a right one.
distance_to_arrival is not offered as a filter: the service ignores it. Setting it to 0-10
light seconds returned the same 1,315 bodies as no filter at all. It is read off each result and
reported, because how far in-system a body sits is half of how far away it is — but it cannot
narrow a search, and offering it as though it could would be the silent-ignore failure with d47’s
name on it.
Hotspots carry the date they were reported, for the same reason outfitting stock does. They are crowd-sourced, and only the rings holding what you asked for are listed — a metal-rich ring with no Painite in it is not part of the answer to “where is Painite”, and naming it invites a trip to the wrong one of two rings around the same planet.
Notes for anyone reading the code
There is no published API for this service; the endpoints are reverse-engineered by every third party that uses them, and the shapes d47 relies on were established against the live service on 2026-08-14. Two that matter:
- a choice filter is
{"value":["Federation"]}— the bare string is a 400 - a range filter is
{"min":"0","max":"20"}, with the bounds as strings
search_reference in a response is a GUID identifying the search, not the system searched from.
The system’s name is reference.name. Reading the wrong one tells the Commander their distances
were measured from 4FF6E786-9829-11F1-A270-E7F8D53241C7.