> ## Documentation Index
> Fetch the complete documentation index at: https://arkor-92aeef0e-eng-353.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Project structure

> Where Arkor expects your code, and what lives in .arkor/ and ~/.arkor/.

A scaffolded Arkor project looks like this:

```
my-arkor-app/
├── src/arkor/
│   ├── index.ts        # createArkor({ trainer })
│   └── trainer.ts      # createTrainer({ ... })
├── arkor.config.ts
├── .arkor/             # per-project state (gitignored)
└── package.json        # dev / build / start
```

Two layers of state matter beyond your source: `.arkor/` (per-project, in the repo) and `~/.arkor/` (per-user, in your home directory).

## `src/arkor/`

Arkor discovers your project by looking for `src/arkor/index.ts`. That file should expose the result of `createArkor()`. The CLI accepts three export shapes (in priority order):

1. **`export const arkor = createArkor({ trainer })`** (preferred, what the templates produce).
2. **`export const trainer = createTrainer({ ... })`** as a power-user shortcut when you do not need the umbrella.
3. **A default export** holding either an `Arkor` manifest or a `Trainer`.

```ts theme={null}
// src/arkor/index.ts (preferred shape)
import { createArkor } from "arkor";
import { trainer } from "./trainer";

export const arkor = createArkor({ trainer });
```

The trainer itself lives in a sibling file by convention so `index.ts` stays thin:

```ts theme={null}
// src/arkor/trainer.ts
import { createTrainer } from "arkor";

export const trainer = createTrainer({
  name: "support-bot-v1",
  model: "unsloth/gemma-4-E4B-it",
  dataset: { type: "huggingface", name: "arkorlab/triage-demo" },
  lora: { r: 16, alpha: 16 },
  maxSteps: 100,
});
```

You can split the trainer further (helpers, prompt builders) however you want; only `index.ts` needs to be at the canonical path.

To register additional trainers in the future, drop more files and pass them through `createArkor`. Today the API accepts a single `trainer`; `deploy` and `eval` slots are reserved on the type but not yet implemented.

## `arkor.config.ts`

`pnpm create arkor` generates a default `arkor.config.ts`:

```ts theme={null}
// arkor.config.ts
export default {};
```

It is currently a placeholder. The runtime does not read fields from it yet. All training defaults live on the `Trainer` itself (`maxSteps`, `learningRate`, `lora`, etc.) so you control them per-trainer rather than at the project level. Leave the file alone unless you have a reason to delete it.

## `.arkor/` (per-project, gitignored)

You should not commit this directory.

* **`.arkor/state.json`**. Project routing: `orgSlug`, `projectSlug`, `projectId`. This is how the runtime maps your local repo to a workspace on the managed backend. The file is created by `ensureProjectState()`, which runs the first time you start training (or hit base-model inference). For **anonymous** workspaces it is auto-created on that first call. For **OAuth** workspaces the runtime errors out instead: today, neither `arkor login` nor `arkor init` populates the file, so you create it by hand with `{ orgSlug, projectSlug, projectId }` and the runtime takes over from there. Once it exists, do not edit it by hand.
* **`.arkor/build/index.mjs`**. Output of `arkor build`: an esbuild bundle of `src/arkor/index.ts` targeting Node 22.6 with bare specifiers kept external. `arkor start` runs this.

## `~/.arkor/` (per-user)

Lives in your home directory, shared across all Arkor projects on the machine.

* **`~/.arkor/credentials.json`**. Auth state. Either an Arkor Cloud OAuth token (written by `arkor login --oauth`, or by choosing `OAuth (browser)` in the interactive `arkor login` picker) or an anonymous token (created on first use if you never logged in). The file is tagged with a `mode` field of `"auth0"` or `"anon"` so the CLI knows which path you are on. `arkor login` writes only this file; it does **not** create `.arkor/state.json`.
* **`~/.arkor/studio-token`** (transient). A per-launch CSRF token written by `arkor dev` (mode `0600`). Used by Studio to authorize calls back into the CLI's local server. Rotated on every `arkor dev` run.

`arkor logout` deletes `credentials.json`. The studio token is removed on process exit on a best-effort basis (it may linger if `arkor dev` crashes) and is rotated on the next launch.

## What the CLI looks for

* `arkor dev` starts the Studio web server at `127.0.0.1:4000` and writes `~/.arkor/studio-token`. It does not file-watch `src/arkor/`. Studio's `/api/manifest` endpoint does call `runBuild` and re-imports with a cache-bust query, but only when the Studio UI fetches it (currently on Run training page mount). If you stay on that page across multiple runs the build artifact is reused; refresh the Run training page (or run `arkor build` from the terminal) between edits to pick up changes. `arkor dev` does not write `.arkor/state.json` on its own.
* `arkor build` reads `src/arkor/index.ts` (or the entry you pass) and writes `.arkor/build/index.mjs`. You only need to call this directly outside the Studio dev loop (e.g. CI, or right before `arkor start` from a script).
* `arkor start` resolves the entry through the runner, rebuilds `.arkor/build/index.mjs` if it is missing or you passed an explicit entry, and runs it (which calls `trainer.start()` and `trainer.wait()`). Triggering training from Studio internally spawns `arkor start`.

Knowing where state lives makes the CLI predictable: if something looks wrong, peek at `.arkor/state.json` and `~/.arkor/credentials.json` before reaching for support.
