Privacy

This page describes what the Euthynos command-line tool does on your machine, what this website loads in your browser, and what happens to an address typed into the early-access form. It is written from the code, not from a template. Where the code has a weakness, it is named here rather than left out.

Last updated 19 August 2026 — the first version of this page.

The short version

The command-line tool sends nothing anywhere. The query path your agent uses makes zero network calls. One flag, off unless you type it yourself, is the only exception in what the tool itself does, and installing it is an ordinary package download. Both are named below.

This website sets no cookies for visitors. No cookie, no localStorage, no sessionStorage, no IndexedDB, no consent banner, no analytics running today. One third party is loaded by the page itself: Google Fonts, on every public page. Two more sit in the request path in front of the site — Cloudflare and then Vercel — and both necessarily see your IP address, because that is what serving a page over the internet requires.

The only personal data this application stores is the early-access form. What you type into it, plus two things the request itself carries: the page you arrived from, and a salted hash of your IP address. Nine values per signup, listed field by field further down. Request logs held by the companies that serve the site are a separate matter, and the section on the host describes them.

The rest of this page is the same three statements with the details attached, plus the parts that are less flattering. Read the sections you care about; nothing important is hidden in the last one.

The command-line tool

Euthynos runs on your machine, against your repository, as you. It reads the working tree — including edits you have not committed — and it reads git history. That is the scope of what it looks at.

What it does:

  • It runs locally. The MCP query path — every tool your agent calls — makes zero network calls and zero calls to any language model. Disconnect the machine and it still answers.
  • It is read-only against your source. It never modifies a file it analysed. The MCP query path your agent uses writes to exactly one place: a .euthynos directory at the root of the repository, holding the content-addressed index and the local log described below. That directory is created with its own .gitignore, so git ignores it by default and it does not get staged unless you force it. You can delete it whenever you like; the next scan rebuilds it.
  • The report commands write wherever you tell them to. That is worth separating from the sentence above, because it is a different thing. euthynos scan takes --json and --md, euthynos graph takes --json, euthynos dashboard takes --out, and euthynos policy and euthynos alerts each take --json and --md. Each writes a file at the path you name on the command line. Nothing writes to one of those paths unless you asked for it on that invocation.
  • There is no account. Nothing to sign up for, no licence key, no activation, no identifier tied to you. Installing and using everything in the repository requires no email address.
  • There is no phone-home. No usage ping, no version check that reports back, no crash reporter, no upload path in the query loop.
  • There is no permissions layer, by design. Euthynos reads the files the operating system has already granted you. The kernel is the authorisation check. It cannot reach anything you could not reach yourself with cat.

The three things that are not nothing

A local log is written by default. It lives inside .euthynos as a file of one JSON record per tool call. It holds metadata only — the tool name, a hash of the arguments rather than their values, response size, timing, whether the cache hit — and it stays on your disk. There is no transmitter attached to it: the file that writes it appends to disk and contains no network primitive of any kind. That is why the site says “no telemetry sent anywhere” rather than claiming none is written. If you would rather it did not exist, set EUTHYNOS_NO_TELEMETRY=1. To skip writing the index at all, set EUTHYNOS_NO_INDEX=1.

One optional flag talks to a third party. Running euthynos scan with the --ai flag sends candidate duplicate code snippets to the Anthropic API and requires you to have set ANTHROPIC_API_KEY yourself. It is off by default, it is not part of the MCP server, and it cannot be triggered by your agent through the tool surface. If you never type that flag, no snippet of your code leaves the machine. Euthynos is not affiliated with Anthropic; that flag is you calling an API you already have keys for.

Installing it is a package download. npm install -g euthynos is an ordinary npm install, so your registry sees that request the same way it sees every other package you fetch. That is between you and your registry, and it is worth saying out loud rather than letting “no network” imply something it does not cover.

How to check this yourself

Do not take the paragraphs above on trust. Two routes are open to you, and both are cheap:

  1. Read the source. The engine is Apache-2.0 and it is published at github.com/euthynos-org/euthynos. The published package, euthynos version 0.1.3, is built from it. Search the query path for anything that opens a socket. If you find one that is not the --ai flag, that is a bug and a security report, and the channel for it is at the bottom of this page. To be clear about the boundary: that repository is the engine. The code behind this website — the signup endpoint and the password-protected admin page — is described on this page but is not in it.
  2. Watch your own network. Attach the MCP server to your agent and point whatever packet capture or outbound firewall your platform gives you at the process. Then unplug the machine and ask your agent the same questions. The answers do not change.

The licence is Apache-2.0 and stays Apache-2.0. That is what makes the first route possible, and the grant already made on every published version cannot be taken back.

This website

Everything in this section describes euthynos.dev as it is deployed today. It is a description of the code and of the observed serving chain, not an undertaking about the future; the last section says how you find out when it changes.

Google Fonts — the one third party the page itself loads

Every public page on this site — this one included, along with the homepage, the research page, the blog index, each of the four posts, the terms page and the contact page — loads two fonts from Google. There are three tags involved: a stylesheet request to fonts.googleapis.com, and two preconnect hints, one to that host and one to fonts.gstatic.com, which is where the font binaries come from.

Preconnect means your browser opens a TCP and TLS connection to Google before it has even parsed the stylesheet link. Contact with Google therefore happens on page load whether or not the fonts are ultimately used and whether or not they are already in your cache.

What Google necessarily receives on each of those requests:

  • Your IP address, because a server cannot send bytes back without one.
  • Your User-Agent string, which your browser sends with every request.
  • A Referer of https://euthynos.dev and nothing more. The site sets Referrer-Policy: strict-origin-when-cross-origin, so Google is told which site you were on, not which page.

There is no consent step and no switch on the page to turn this off. Blocking those two hosts at your resolver, or using a font-blocking extension, stops it — the site falls back to your system fonts and everything still works. This is the honest cost of the typeface. It could be removed by self-hosting the font files. It has not been.

One piece of wording worth pinning down, since it appears on every page of this site: “no telemetry sent anywhere” describes the engine that runs on your machine. It does not describe this marketing site, which contacts Google on every page load and is served through two companies named next.

The two companies in front of this site

euthynos.dev is deployed on Vercel, as a project called euthynos. It is not served directly from Vercel to you. Cloudflare sits in front of Vercel, and both are in the path of every request you make. This is visible in the response headers the site returns today: a Server: cloudflare header, a CF-RAY identifier and a cf-cache-status value arrive alongside Vercel’s own x-vercel-cache and x-vercel-id headers.

The order matters, so it is stated plainly. Cloudflare is first. It terminates the TLS connection your browser opens, which means Cloudflare — not Vercel, and not any code written here — is the first party to see your IP address, your user agent, the URL you asked for and the time you asked for it. It decrypts the request in order to forward it. Vercel then receives the same request behind it and sees the same fields. Both companies process that data as infrastructure. That is not a decision made about your data after the fact; it is what this serving chain is.

Cloudflare’s edge also sends your browser a reporting instruction. The responses carry Report-To and NEL headers — Network Error Logging — naming an endpoint at a.nel.cloudflare.com. That directive asks your browser to send Cloudflare a report when a request to this site fails at the network level. It is a request your browser may make to Cloudflare that no tag on this page asked for, and it comes from the edge rather than from the site’s own code. It is disclosed here because a reader counting outbound destinations would otherwise miss it.

Typing the www address costs one extra request. www.euthynos.dev answers with a redirect to the apex domain. If you arrive that way, Cloudflare sees the redirected request as well as the one that follows it.

Cloudflare and Vercel each keep request logs under their own terms, and those logs are outside this application’s control. What the application code contributes to them is nothing personal: when the signup endpoint fails it logs an error code or a message, never the address, the IP or the request body.

One thing to keep separate, because the name repeats: Cloudflare Web Analytics is not running on this site. It appears further down as one of two analytics snippets that sit commented out in the page source. Cloudflare being in the serving path is a different fact from Cloudflare Web Analytics being switched on, and only the first of those is true today.

Before any of that, your browser has to resolve euthynos.dev to an address. That DNS lookup goes to whichever resolver your machine or network is configured to use, and on to the nameservers for the domain. Whoever operates those sees that a resolver asked for this domain. The address that comes back is a Cloudflare edge address, since Cloudflare is what answers. Nothing from that lookup reaches this site, and it is not something the site can see or switch off.

Analytics: none is running

No analytics provider is active on this site today. Two snippets exist in the source of the homepage, the research page, the blog index and the four posts — Cloudflare Web Analytics and Plausible — but both sit inside an HTML comment block, so your browser never parses them as scripts and never requests either host. The blog generator emits the same commented block, so a newly published post ships the same way. This is not an accident of one file. This page, the terms page and the contact page are built from a different template and carry neither snippet at all.

Being more forthcoming than is comfortable: on the homepage, the research page, the blog index and the four posts — not this page, the terms page or the contact page — two click listeners are attached on every such page and they do run. One fires when you click a copy button. The other fires on any outbound link and reads the full destination URL. Both then hand what they collected to a function whose body does nothing, because no provider is loaded. Nothing is sent, nothing is stored, and the value is discarded when the function returns. The instrumentation exists, though, and you should hear that here rather than find it in the source.

If a provider is ever switched on, this is what changes:

  • It would be one of those two. Both are documented by their operators as cookieless and as not building cross-site profiles. That is their description of their own product, not something verified here, and either could change how it behaves without telling this site.
  • Those two events would begin transmitting — including, for an outbound click, the address of the site you are leaving to.
  • Do Not Track and Global Privacy Control are already checked before that call. A browser sending either signal would send no events at all.
  • This page would name the provider, and the date at the top would move.

One correction to a claim that is easy to overstate: those Do Not Track and Global Privacy Control checks gate the analytics layer only. They do not stop the Google Fonts requests, and they have no bearing on what Cloudflare and Vercel see, both of which happen before any script on the page runs.

Cookies and browser storage

A visitor to this site receives no cookies from it. There is no call to document.cookie, no localStorage, no sessionStorage and no IndexedDB anywhere in the site. There is no consent banner because there is nothing that would need one, other than the Google Fonts question above, which a banner would not honestly solve.

Exactly one cookie is set by this application, named euthynos_admin. It is set only after a successful password login to the private admin page, so an ordinary visitor never receives it. Its flags are HttpOnly, Secure, SameSite=Strict, Path=/, and a maximum age of 28,800 seconds, which is eight hours. Its value contains an expiry timestamp, a random 12-byte nonce and an HMAC-SHA256 signature over both — no personal data of any kind.

The weakness in that design, stated because it is real: the session is stateless, with no server-side store. Signing out clears the cookie in the browser but revokes nothing. A token that leaked would stay valid until its own expiry, up to eight hours later.

What else the page loads

  • No tracking pixels, iframes, embeds, videos or remote images. The only <img> tag on the entire site is a same-origin SVG chart. The social preview images are hosted on euthynos.dev.
  • Icons: one is inline, the rest are real requests to this site and no one else. The main page icon on the homepage, the research page, the blog index and the four posts is an inline SVG data URI, which is not a network fetch. Everything else is an ordinary request to euthynos.dev: /apple-touch-icon.png on every public page, and /favicon.ico on this page, the terms page, the contact page and the admin page.
  • Outbound links are navigation, not loading. The links to GitHub, npm and X do nothing until you click them. Those hosts are contacted because you chose to go there.
  • The admin page loads no external host at all. It uses system font stacks, is marked noindex and no-store at the edge and in the handler, and is disallowed for general crawlers in robots.txt. One caveat, since it undercuts that last clause: the five AI crawlers named below each have their own robots.txt group containing only an allow rule, and a crawler follows the most specific group that matches it and ignores the general one. The /admin and /api/ disallow lines therefore do not apply to those five. The noindex header is what actually covers that case.
  • robots.txt invites AI crawlers. GPTBot, ClaudeBot, PerplexityBot, Google-Extended and CCBot are explicitly allowed to crawl all public content. That is a deliberate choice about the published text on these pages. It has nothing to do with visitor data, which is not in any crawlable page.

One further limit worth naming: there is no Content-Security-Policy header on this site. The list above is a description of the code as it stands, not something the browser is enforcing. Nothing at the browser level would stop a future script from contacting a host that is not named here.

The early-access list

Euthynos for teams is not open. The form on the homepage exists so that there is a way to tell you if it does. Nothing on this page commits to it opening at all — it may never open, and signing up is not a place in a queue for something that has been decided on.

Nine values are written to the database per signup. The table below lists all nine, plus one extra row for the hidden field your browser sends that is deliberately never written.

FieldRequired?Why it is asked
Email address Required The single reason the form exists: one email if early access opens. Stored exactly as you typed it.
Lowercased copy of your email Not asked — derived It is the uniqueness key on the table. It stops the same address arriving twice with different capitalisation and creating two rows.
Your agent Optional Which agent a pull-request integration would be tested against first, if one is built. Prefer not to say is the default, and choosing it stores no value at all — the column is left empty.
Team size Optional Whether to build for one repository or fifty first. Same default, and the same empty column when you leave it alone.
What would you want it to catch? Optional, free text Build order. It is the most useful field on the form and the one to be careful with: it is stored verbatim, and it appears in the admin table and the CSV export. The browser caps it at 300 characters and the server accepts up to 2,000. Left blank, it is stored as nothing at all rather than as an empty string. Do not put anything confidential in it.
Company Not for you A hidden bot trap. Your browser transmits it empty on every submission and it is never stored. If it arrives filled in, the server returns a success response and writes nothing at all.
Referring page Not asked — captured The page that sent you here, read from document.referrer, cut to 300 characters by the browser and capped again at 400 by the server. It is how a post gets judged as worth writing. If you arrived by typing the address, it is blank, and blank is stored as nothing rather than as an empty string. Read the paragraph below before you decide that is fine.
Hash of your IP address Not asked — derived Rate limiting: at most five signups per IP hash per hour. The mechanism, and what it does and does not protect, is described below.
Row number and timestamp Automatic An auto-incrementing id and the time the row was written. The timestamp is what the rate-limit query counts against.

The referring page, said plainly

If you arrive at euthynos.dev from a private, internal or search-result URL, that URL is stored in the same row as your email address. This is not hypothetical — it is what document.referrer contains. If that is a problem for you, open euthynos.dev in a new tab and type the address, or sign up from a plain link; the field is then empty.

How the IP address is handled

This application never writes your IP address in readable form. The address is taken from the first entry of the x-forwarded-for header that the proxy in front supplies, falling back to the socket address. It is then joined to a salt held in an environment variable, hashed with SHA-256, and truncated to the first 32 hexadecimal characters — 128 bits. Only that truncated hash is written.

That is a statement about this application, not about the whole stack. Cloudflare and Vercel both handle your raw address in order to route the request at all, as the section above describes, and what their logs retain is governed by their terms rather than by this code.

What the hash is not: it is not anonymous. It is pseudonymous. The IPv4 space is small enough to enumerate, so anyone holding the salt can reverse the hash back to an address by brute force. The salt is what makes the hash worth anything, so the handling of the salt is worth stating exactly. It is read from an environment variable, falling back to a second one, and there is no default written into the source. If neither is set to at least 16 characters the endpoint refuses the request outright and stores nothing, rather than computing a hash a public salt would make reversible. An earlier version of this code did carry a fallback value in the source; it has been removed, and the endpoint now fails closed instead.

The hash also does not expire. It is written into the same row as your email address, it is indexed so the rate-limit query can read it back, and nothing deletes it. Its purpose is rate limiting; its lifetime is the lifetime of the row. Any policy that told you IP data was used transiently and then discarded would be describing different code.

How long it is kept

Indefinitely, until someone removes it by hand. There is no retention limit, no expiry job, no purge script and no deletion endpoint anywhere in the codebase. A row, once written, is removed only by running a statement against the database. If you want yours gone, the route is the email address in the rights section below, and it is done manually.

There is also no unsubscribe link, because there is no mailing to unsubscribe from. What the form is for is one email if early access opens, and nothing else, and no code exists that could send anything more. If you want off the list before then, email and say so.

Who can read it

One person: Tonil Kumar, through a password-protected admin page that ordinary visitors cannot reach. That page reads the list through an endpoint that returns id, email, agent, team size, the free-text answer, referrer and timestamp, capped at 5,000 rows. It deliberately never returns the IP hash.

The same page can export the whole list — every email address, every free-text answer and every referrer URL — as a CSV file downloaded to that machine. Once a CSV is on a laptop it is a file on a laptop, and no policy language changes that. It is mentioned here because it is true, not because it is reassuring.

The mechanisms protecting that page, named rather than gestured at. The admin password is never stored anywhere, only a scrypt hash of it held in an environment variable and compared in constant time. Failed logins are counted per caller and cut off at eight in a 15-minute window, with a one-second delay on every failure. That counter deserves an honest description rather than a flattering one: it lives in the memory of a single serverless instance, so it resets when the instance recycles and it does not span concurrent instances. It is a speed bump, not a ceiling. The real brake is scrypt’s cost plus the one-second delay on every wrong answer. The key that counter is filed under is an unsalted SHA-256 of the caller’s IP, truncated to 24 characters, held in memory only — never written to the database and never written to a log.

Where it physically lives

Your email address sits in a PostgreSQL database, reached over the network by the node-postgres driver from a serverless function running on Vercel. The connection string is supplied by the hosting environment, and the code comments name Vercel Postgres and Neon as the intended provider. Vercel and that database provider therefore process this data as infrastructure; that is unavoidable if the data is to exist at all.

Two honest gaps rather than two invented answers:

  • No region is pinned. The deployment configuration names no region for either the functions or the database. I will not tell you which country the rows sit in, because the code does not establish it.
  • The database connection is encrypted but not verified. The driver is configured with certificate verification turned off, because the certificate authority for a provider-issued connection string is not pinned. Traffic to the database is in TLS; the server’s certificate is not checked against a chain. That is weaker than it should be, it is still true as this page is published, and it is stated rather than dressed up.

Two smaller behaviours you may as well know. If no database is attached, the signup endpoint returns an error rather than accepting your address and dropping it — there is no state in which you are told you were added and were not, with one exception, the bot trap described above. A submission that arrives with the hidden company field filled in gets the same success response and writes nothing. That field is positioned off-screen rather than removed from the form, so an aggressive form-filler could in principle trip it and you would be told you were on the list when you were not.

And if you sign up twice, the second submission writes nothing and the response is byte-identical to the first. This is deliberate. Telling you “you were already on the list” would turn an open, unauthenticated endpoint into a way for anyone to test an address and learn from the answer whether its owner had signed up, so the endpoint returns the same thing either way and the page shows one message either way: You are on the list. One email if and when it opens. The nicer copy was not worth the leak.

What is never done

  • Nothing is sold. Not the list, not a segment of it, not an aggregate derived from it.
  • Nothing goes to advertisers, ad networks or data brokers. There is no advertising on this site and no plan for any.
  • No profile is built. The row is a row. Nothing enriches it against another dataset, scores it, or looks up who you are from your address or your IP hash.
  • There is no cross-site tracking. There is nothing on this site built to do it: no cookie, no browser storage, no pixel, no fingerprinting script, no ad network, no identifier that survives a page load. The one thing a third party sees on every page load is the Google Fonts request named above, and Google sees that on every site that makes it.
  • No dark patterns. Optional fields are labelled optional and default to prefer not to say. There is no pre-ticked box, no consent dialogue where declining is the harder path, no fake countdown, and no email wall in front of the download. The CLI takes no address at all.

One qualification, so that list stays true. It describes what is done with your data here. It is not a claim that no third party ever sees anything. The parties that do, all named earlier on this page, are: Cloudflare and Vercel, which serve every request and see your IP address, user agent, URL and timestamp; the database provider, which holds the rows; Google, which receives your IP and user agent on every page load through the fonts request; Cloudflare again, if your browser acts on the network-error reporting directive its edge sends; your npm registry, if you install the package; your DNS resolver and the domain’s nameservers, when you look the address up; and the Anthropic API, if you type the --ai flag yourself. That is every third party this site’s code and this project’s serving chain involve.

Your rights, and the route to them

If you are on the early-access list you can ask for any of the following, and there is exactly one address to ask at: [email protected].

  • Access. Ask what is stored about you, and the reply lists the values in your row.
  • Correction. A typo in an address, or a free-text answer you would rather change or remove.
  • Deletion. The whole row goes, including the free-text answer, the referrer and the IP hash. Not flagged, not hidden — deleted.
  • A copy. The values from your row, sent back to you in a plain machine-readable form.
  • Objection. Tell me not to use your data for something and it stops, or the row goes if you would rather that.

None of these is a button, because no code implements one. Every one is done by hand by one person maintaining a project, not a staffed support desk, so there is no guaranteed turnaround and no clock is set here. Requests are worked through as they are read, and a deletion is confirmed by reply once it has been done.

Verifying you are the person whose address it is: replying from the address on the list is enough, and it is the only check applied, so keep the request coming from that mailbox. And the obvious point that policies usually skip — an email you send is itself data. It sits in a mailbox until it is deleted, along with whatever you chose to put in it.

Children

Euthynos is a developer tool. It is aimed at people who write software professionally, and this website is written for them. Neither is directed at children, and nothing here is designed to appeal to them.

No age is asked for and none is stored, so there is no age check and no claim that one exists. If you believe a child has been added to the early-access list, email [email protected] and the row is deleted.

Changes to this page

This page describes code. When the code changes, the page changes with it. The signals are:

  • The date at the top. It is meant to move whenever anything on this page is edited, and it is the fastest way to tell that something did.
  • A line saying what changed. For anything that affects data already collected — a new third party the pages load, a change in who serves the site, an analytics provider switched on, a new field on the form, a retention rule that finally exists — this page is meant to say what changed, rather than quietly read differently.

There is no notification list for this page, and there is no intention to add one, because that would mean collecting more addresses in order to describe how few are collected. If early access opens and you are on the list, the one email you receive is meant to point here if anything material has moved.

19 August 2026. First version of this page.

How to get in touch

Anything about this page
[email protected] — access, correction, deletion, a copy, an objection, or a question about a sentence here you think is wrong.
A bug or a question about the tool
GitHub issues. Public, so do not put anything private in one.
A security vulnerability
Report it privately through the security policy, not in a public issue — a public issue is a disclosure. Response is best-effort: there is no staffed security team, and no acknowledgement time is guaranteed.
The source
github.com/euthynos-org/euthynos, Apache-2.0. Published as euthynos on npm.
Occasional updates
x.com/EuthynosDev.
Who is responsible
Tonil Kumar, as an individual. There is no company behind Euthynos, and nothing on this page should be read as implying one.