# Security and privacy

June is a library that runs in your process. It has no server and sends nothing to June itself: data leaves your machine only when your code calls a model, a provider or a trainer, and June writes files only where you point a store or a trainer. This page collects what goes where.

Training data, chat sessions and corpora are often sensitive: a person's private writing, customer emails, internal docs. Treat everything below that holds them the same way.

## Data flow at a glance

| Surface             | May send externally                                                      | May persist                                                                                |
| ------------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ |
| Workflows and steps | prompts, messages and tool data, to the models and tools you configure   | traces, results and snapshots, wherever your code saves them                               |
| Chat                | each turn's instructions, context and input, to the responder's model    | the session journal, in the `ChatStore` you choose                                         |
| Copy                | corpus text and requests, to the teacher, writer and judge models        | voice manifests, and prepared samples, wherever your code saves them                       |
| Evals               | case inputs, to the target and any model-based grader                    | eval runs, wherever your code saves them                                                   |
| Local training      | nothing but downloads: base model weights and Python packages            | a run directory under `.june/trl` with the training data and weights; uv and HF caches     |
| Managed training    | the training and validation datasets and the job config, to the provider | staging objects in your Cloud Storage bucket and the tuned model, at the provider          |

"Local" holds only as far as every model involved is local: a hosted teacher, judge, grader or eval target still receives the text you give it. Fingerprints and hashes identify data; they aren't a confidentiality mechanism. Each provider keeps what it receives under its own terms and retention, and that's between you and the provider.

The sections below give the detail.

## What leaves your machine

| What runs                         | What leaves your machine                                                                                                                    |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| a `<Step>`                        | the agent's instructions and tool definitions, the prompt, and the loop's messages and tool results, sent to the agent's model on each call |
| a tool                            | whatever your tool's code sends; `<Bash />` can run commands that send anything the process can                                           |
| `useStep()`                       | whatever your function sends                                                                                                                |
| a chat turn                       | the instructions, the context and the new input, sent to the model or workflow answering it                                                 |
| `summaryContext()`                | the turns it summarizes, sent to the summarizer model                                                                                       |
| `dataset()`, splits, fingerprints | nothing                                                                                                                                     |
| `evaluate()`                      | each case's input, sent to the target (and any model-based grader)                                                                          |
| `trl()`                           | nothing but downloads: the model weights and Python packages. Training data stays local                                                     |
| `vertex()`                        | the training and validation datasets, uploaded to your Cloud Storage bucket, and the job                                                    |
| `prepareVoice()`                  | each sample's text and metadata, sent to the teacher model you chose                                                                        |
| `voice.write()`                   | the request and exemplar texts, sent to the writing model; candidates, to the judge                                                         |
| `june doctor`                     | nothing: it checks whether keys are set, not whether they work                                                                              |

When the data can't leave, use local models for the teacher, judge, graders and eval target too, not only for training.

Managed training stores your data with the provider. Delete the staging objects and tuned models when you're done with them.

## What June writes to disk

June's own code writes files in two places, and only when you use them:

- **`fileStore(dir)`** writes one JSONL journal per chat session in `dir`. See [Chat](#chat).
- **`trl()`** writes a run directory under `.june/trl` (or its `dir` option) holding a copy of the training data, the config, the runner's log, and the trained weights. See [Local training](https://june.dev/docs/training/local.md#runs-and-their-files). uv and Hugging Face also cache the packages and base model weights they download in their own cache directories.

Everything else June produces it returns to you as values: run results and traces, snapshots, job refs, training and voice manifests, eval runs and datasets. Where they're saved, and who can read them, is up to your code.

Treat `.june/` as sensitive and keep it out of version control.

## Credentials

June doesn't take model API keys: AI SDK providers read them, usually from the environment. `june doctor` only checks whether they're set and never prints their values.

Pass other credentials only where an option asks for them, such as `vertex({ getAccessToken })` or `trl({ env: { HF_TOKEN } })`. June sends tokens only in request headers and keeps them out of refs, manifests, errors and traces. Don't put secrets in `providerOptions`, metadata, dataset metadata or prompts: those are meant to be stored and passed around.

The TRL runner gets your process's environment, plus `trl({ env })`, so it can read the same variables your app can.

## What June's records hold

- **Run snapshots** hold each finished step's result and cache key, as plain JSON. A result is whatever the step produced, model text included.
- **Traces** (`onUpdate`, the resolved `tree`, `june run --json`) hold each step's prompt, status, timing, model id, usage, tool calls with their inputs and outputs, streamed text and result. An `<Agent>`'s node holds its id, model id and tool names, not its instructions or model settings. A `<FineTune>`'s node holds its job id, state, progress and result, and an `<Evaluate>`'s its results, which include case inputs and outputs. Traces never hold the training request or provider options.
- **`june run`** prints step progress and tool inputs to stderr, and results to stdout. It never prints `--input` itself, even in errors, though input your workflow puts in a prompt or a result appears wherever those do, including `--json`'s `tree`.
- **Training manifests** record the base model, trainer, method, hyperparameters, dataset sources, sizes and fingerprints, the job ref and the artifact. They don't hold examples or `providerOptions`.
- **Voice manifests** record the voice's name, the corpus's source, size and fingerprint, the artifact and training manifest if it was trained, and its settings. They don't hold the corpus's text.
- **Job refs** hold what a trainer needs to find its job: ids, resource names, a run directory.
- **Dataset fingerprints** are SHA-256 hashes. They identify data; they don't hide it from someone who can guess it.

## Tools that run commands

`<Bash />`, and `bashTool()` from `june/tools` under it, runs commands on your machine with your process's permissions and environment. It is not sandboxed, and approval is a prompt for an operator, not a boundary. Commands and their output appear in traces and go to the model. See [Tools](https://june.dev/docs/workflows/tools.md#where-it-runs).

## Chat

A chat session's journal holds inputs, replies, steering, feedback and small provenance, in plain text. It never holds API keys, auth headers, instructions, raw provider requests or responses, workflow traces, or tool inputs and outputs, except where a reply itself quotes them. `fileStore()` creates its directory as `0700` and each journal as `0600`, where the platform supports it, but doesn't encrypt them; `memoryStore()` keeps sessions only for the life of the process; your own `ChatStore` owns its access control, encryption and retention. June stores what it's given and doesn't authenticate who reads a session. See [Chat: privacy and security](https://june.dev/docs/chat/privacy.md) and [sessions and stores](https://june.dev/docs/chat/sessions.md).

## Training on what people wrote

Chat sessions, feedback and corpora become training data only when your code converts them; `june/train` reads sessions and never writes to their journals. Before training, read what you're about to train on: feedback is written by people, edits can carry mistakes or private data, and a session's content already went to whatever model answered it. See [Learning from chat](https://june.dev/docs/chat/learning.md).

A voice is a model of a real person's writing. Train one only with their consent, on writing that's theirs: [authorship hygiene](https://june.dev/docs/copy/corpora.md#authorship-hygiene) keeps other people's words out of a corpus.
