# Files

Everything `evoke` reads or writes in a project, and who owns each file.

```text
<project>/
├── evoke.toml            yours          the adapter, the reflexes, their settings
├── evoke.lock            evoke's        written whole by add, update and remove; realised by sync
├── evoke.d.ts            evoke's        written with the lock: Reflexes, for load<Reflexes>
├── overlays/<name>.toml  yours          your wording for one reflex, by local name
└── vocab/<name>.toml     yours          your words, by vocabulary name

<reflex>/
├── reflex.toml           the author's   the manifest
├── <body>.mts            the author's   the file run names; nothing for an argv, or for a playbook, whose body is steps
└── reflex.d.ts           evoke's        written by check: Args, Config, Context, Result, Reflex
```

`evoke` edits your files in place, keeping comments and order. It verifies each write by reading it back. On
failure it writes nothing, and prints the line. The lock and the two `.d.ts` files are rendered whole. A file that
is a symlink is written through; the link stays.

## `evoke.toml`

```toml
adapter = "jev"                    # required; a name resolved against evoke's built-ins, never a path

[reflexes]                         # local name = ref
lights = "radhi/home/lights"       # owner/repo[/dir]: unpinned, update moves it
timer  = "radhi/timer@1.0.1"       # @tag pins it
clock  = "https://git.example.com/clock.git#clock@2.0.0"   # any git host; https or ssh; #dir and @tag optional
hello  = "./hello"                 # a local directory, relative to this file; never locked

[config.lights]                    # per reflex, the keys its [config] declares
bridge = "10.0.0.2"                # plain
token  = { env = "HUE_TOKEN" }     # from a variable; the only form a secret may take

[adapters.jev]                     # per adapter, under its name; inert unless selected
gate = { route = 0.5, fits = 0.3, read = 0.8, write = 0.9, whole = 0.3 }   # each a probability; read ≤ write
```

The built-in adapters are `jev`, `openjev`, `clef`, `clef_flash` and `replay`; `[adapters.openjev]` takes the same
`gate` table as `[adapters.jev]`. `clef` and `clef_flash` ship no thresholds, so a `gate` table of theirs gives
`route`, `read` and `write`. Local names match `[a-z][a-z0-9_]*`. The names `none`, `unstated`, `fits` and `weave` are reserved. A missing `evoke.toml`
at a root means the default project: `adapter = "jev"`, nothing installed.

## `evoke.lock`

```toml
lock  = 1
evoke = "0.1.0"

[adapter]
name = "jev"
id   = "jev-1.13.0"

[reflexes.lights]
ref    = "radhi/home/lights"
tag    = "1.2.0"
commit = "7a498d11d5375f3cb65c575c3186bc64ecac7f52"
h1     = "h1:a30b1bbcf52390c4b1311685ceee9f886b81b7699cde1374040979ad00c25d3a"
effect = "write"
```

Per remote reflex: the ref without its pin, the tag, the commit, the content hash of the reflex directory, and the
effect you consented to. Local reflexes are not locked. `h1` is a SHA-256 over `sha256sum`'s own lines for every
file in the directory. Files are taken in byte order of path, and the project's five names are skipped:

```bash
find . -type f | sed 's|^\./||' | LC_ALL=C sort | xargs sha256sum | sha256sum
```

## `overlays/<name>.toml`

```toml
description = "…"                                   # replaces whole
not_for     = ["…"]                                 # replaces whole
tags        = ["…"]                                 # replaces whole
effect      = "destructive"                         # may only tighten
confirm     = "…"                                   # placeholders name required arguments

[args.state]                                        # by its current name, or a former one declared with was
ask = "…"
options.dim = "…"                                    # new wording for an existing key only

[examples]                                          # sent; may assert vocab arguments
"kill the lights" = { state = "off" }

[tests]                                             # held out; a shipped example named here stops being sent
"light a candle" = false
```

A contract key in an overlay makes the reflex inactive: `run`, `config`, `yields`, and an argument's source, range,
flag or `optional`. A key that addresses nothing the reflex has, an argument or an option key of its own, is
orphaned: skipped, and reported by `update`.

## `vocab/<name>.toml`

```toml
den    = "The TV room downstairs; also 'the snug'."
office = { what = "The upstairs study.", value = "group-7" }
```

A word is one clean line, trimmed, spaces allowed, and unique under identity. `none` and `unstated` are reserved.
`what` is what the classifier reads. `value` is what the body receives instead of the word.

## `evoke.d.ts`

```ts
// Generated by evoke add, update and remove; do not edit.
// What a decision's args carry, per installed reflex: load<Reflexes> narrows them by reflex.

export type Option<K extends string> = { type: "option"; key: K }
export type Word = { type: "word"; word: string; value?: string }
export type Pick<T extends string, V> = { type: "pick"; span: { start: number; end: number; text: string }; value: { type: T; value: V } }
export type Day = { type: "offset"; days: number } | { type: "weekday"; weekday: "monday" | "tuesday" | "wednesday" | "thursday" | "friday" | "saturday" | "sunday"; which?: "next" | "this" | "last" } | { type: "day"; day: number } | { type: "calendar"; year?: number; month: number; day: number }
export type Flag = { type: "flag" }

export interface Reflexes {
  timer: {
    /** How long? */
    duration: Pick<"duration", number>
    /** What is the timer for? */
    label?: Pick<"quoted", string>
  }
}
```

A date is `Pick<"date", Day>`, a time `Pick<"time", string>`, an amount `Pick<"amount", { amount: number; currency:
string }>`, a code `Pick<"code", string>`. A reflex whose manifest does not read is left out. The file imports
nothing.

## `reflex.d.ts`

```ts
// Generated by evoke check; do not edit.

export interface Args {
  /** How long? */
  duration: number
  /** What is the timer for? */
  label?: string
}

export interface Config {}

/** What the body receives beside its arguments. */
export interface Context {
  /** The person's own words, or the step's words in a plan. Empty when `evoke run` calls it by name. */
  input: string
  config: Config
  /** Aborted at the deadline, on Ctrl-C or SIGTERM, when an app cancels the run, and when evoke ends: stop. */
  signal: AbortSignal
}

/** What the body returns: the text a person reads, and data an app may use. */
export type Result = string | { text: string; data?: unknown }

/** The body: the default export of the file `run` names. */
export type Reflex = (args: Args, context: Context) => Result | Promise<Result>
```

Written for a file body only, and only when it changed.

## A plan file

`evoke try --save <file>` writes one; `evoke run <file>` runs it. It is yours, wherever you put it; `<name>.plan.json`
is the recommended name. Written whole as JSON, its second line says what it holds:

```json
{
  "note": "Written by evoke try --save: the sentence and the classifier's answers, in clear. evoke run runs it exactly, or says which pin moved.",
  "plan": 1,
  "input": "pull september's bank transactions, invoices, card expenses and payroll, reconcile them, post the closing entries to the ledger, then send the report to cfo@example.com",
  "weave": { "input": "…", "steps": [ { "n": 1, "text": "pull september's bank transactions", "decision": { "call": "bank month=\"september\"", … } }, … ], … },
  "evoke": "0.10.1",
  "adapter": { "name": "jev", "id": "jev-1.13.0" },
  "gate": { "route": 0.5, "fits": 0.3, "read": 0.8, "write": 0.9, "whole": 0.3 },
  "set": "h1:…",
  "reflexes": { "bank": { "item": "h1:…", "path": "./bank" }, "ledger": { "item": "h1:…", "ref": "acme/books/ledger", "tag": "1.2.0", "h1": "h1:…" }, … },
  "vocab": { "months": "h1:…" },
  "answers": [ { "text": "pull september's …", "raw": { "weave.split_0": { "yes": 0.9 }, … } }, … ]
}
```

The file holds, in clear, the sentence, the words it used, and every number the classifier answered; it holds no
setting's value, no variable and no key, and no time and no name. A remote reflex is pinned by the lock's `h1`; a
local reflex's body is not pinned, as it is not locked. `grep '"call"'` lists the calls.

## Machine-local files

These live outside every project, under XDG paths. The store, the answer cache and the test baselines are in
`~/.cache/evoke/`. The log, trust, the runtime path and the REPL's history are in `~/.local/state/evoke/`.
[Environment](environment.md) lists each.
