> ## Documentation Index
> Fetch the complete documentation index at: https://www.chapterjs.org/llms.txt
> Use this file to discover all available pages before exploring further.

# A tour of the project

> What each file of your project is for, the one rule that organises them, and how the editor and the hot reload help you

Your project runs. Before changing it, take a tour: a ChapterJS project is small, and once you know what each file is for, you know where everything goes for the rest of the tutorial.

**buddy**

**.chapterjs**

**node\_modules**

**public**

**src**

**presence.ts**

**.env**

**.env.example**

**.gitignore**

**package.json**

**tsconfig.json**

## The one rule: what a file exports says what it is

Everything your bot does lives in `src/`. ChapterJS never asks you to register anything: it loads every file of `src/`, and what the files **export**, made with one of its functions, is what the bot runs. The template has one file, `src/presence.ts`: what Discord shows under the name of your bot, "Getting ready". Add a second one, a command, in `src/commands/ping.ts`:

```ts src/commands/ping.ts theme={"theme":{"light":"github-light","dark":"vesper"}}
import { command } from 'chapterjs';

export default command({
  name: 'ping',
  description: 'Replies with Pong!',
  async run({ interaction }) {
    await interaction.reply('Pong!');
  },
});
```

Save: the terminal says `↻ Reloaded in 12 ms, 1 command, a presence loaded`, then `↻ Commands updated on My Server`, and `/ping` is in your test server. Nothing else says "this is a command": `command()` does. Its `name` is what people type after the `/`, and the file only says what the command *does*. Change `name` to `'hello'`, and the command becomes `/hello`; move the file to `src/fun/ping.ts`, and nothing changes.

That is the rule for everything the framework runs:

| Declared with | What it is |
| - | - |
| `command({ name, ... })` | A slash command: `name: 'ping'` is `/ping`, `name: 'mod ban'` is `/mod ban` |
| `event({ name, ... })` | A reaction to an event: `name: 'memberJoin'` runs when someone joins |
| `button({ ... })`, `select({ ... })`, `modal({ ... })`, `embed(...)` | A button, a select menu, a form or an embed, named by its export: `export const vote = button(...)` is the button `vote` |
| `task({ ... })` | Something the bot does by itself, every so often or at given times, named by its export |
| `language({ locale, ... })` | One language of the bot: `locale: 'fr'` is French |
| `presence({ ... })` | What the bot shows under its name, declared once |

A file may declare several of them, and a file that declares none is plain code: `src/lib/`, `src/db/`, anything you import from the others. The templates of `create chapterjs` do both: your project keeps a folder per kind (`src/commands/`, and later `src/events/`), and `tickets` puts everything about tickets in `src/tickets/`: the command, the form, the buttons, and their texts in both languages. A folder is only a folder.

Why this design? Because the alternative, a list somewhere that says "the `/ping` command is in this file, the welcome event is in that one", is a list you have to keep in sync with your files by hand. Here, there is no list. Adding a command is adding a declaration; removing one is deleting it.

## The same import everywhere

Every file starts with `import { command } from 'chapterjs'`, or `event`, `button`... All of them come from the same package, `chapterjs`. There is nothing else to import: no client, no configuration, no file of the framework. And each function knows what to expect from what you give it: `event({ name: 'memberJoin' })` gives your function a member, `event({ name: 'messageCreate' })` a message, with the same import line.

## `.chapterjs/`: generated, ignored, safe to delete

This folder is written by the framework, and git ignores it. It holds what your **project** adds to the types of `chapterjs`: the files of `public/` that `asset()` offers, your languages, which type `t`, and your commands. Your editor reads it to complete what you type and to underline a mistake. It also keeps a small cache (what was last registered with Discord, so that starting again costs nothing) and, later, the compiled bot.

It is written when you install the project (`postinstall` runs `chapterjs sync`) and every time `chapterjs dev` starts. If your editor ever says that it does not know the files of `public/` or your texts, run `chapterjs sync` (`pnpm chapterjs sync`, or the equivalent) and reload the editor. You can also delete the folder: it is rebuilt.

## Try the editor

Open `src/commands/ping.ts` in your editor, and in `run`, type `interaction.` with the dot. The editor lists everything an interaction can do: `reply`, `defer`, `edit`, `followUp`, `delete`... Now type `interaction.replu('Pong!')` with a typo: it is underlined before you even save, with the method it does not know.

This is what "no type to write" means. Your files are TypeScript, so that the editor can do this, but every type comes from the framework. You never write one.

> [!NOTE]
>
> If nothing is underlined and nothing is completed, your editor is not reading
> the types. In Visual Studio Code, make sure the folder you opened is the
> project itself (the one with `package.json`), not a folder above it, and run
> `chapterjs sync` once.

## Try the hot reload

Start the bot (`pnpm dev`) and leave it running. Change the answer in `src/commands/ping.ts`:

```ts src/commands/ping.ts theme={"theme":{"light":"github-light","dark":"vesper"}}
import { command } from 'chapterjs';

export default command({
  name: 'ping',
  description: 'Replies with Pong!',
  async run({ interaction }) {
    await interaction.reply('Pong! 🏓');
  },
});
```

Save. The terminal says:

```text theme={"theme":{"light":"github-light","dark":"vesper"}}
↻ Reloaded in 12 ms, 1 command, a presence loaded
```

Use `/ping` again in Discord: the new answer. You never restart the bot while you write it: every file of `src/` is watched, and a save reloads it, along with every file that imports it.

Now break the file on purpose: delete `'Pong! 🏓')` so that the line reads `await interaction.reply(;`, and save.

```text theme={"theme":{"light":"github-light","dark":"vesper"}}
✗ src/commands/ping.ts:6 Expression expected
⚠ Reloaded with an error: that file keeps running its last working version
```

The bot is still online, and `/ping` still answers with the last version that worked. Fix the file, save, and it reloads. A mistake never takes the bot down, so you can try things freely.

## The other files

| File | What it is |
| - | - |
| `public/` | The pictures and files your bot sends. Empty for now; a later chapter uses it. |
| `node_modules/` | The packages installed by your package manager, `chapterjs` among them. Never edit it, never commit it. |
| `.env`, `.env.example` | The values your bot needs (the previous page). |
| `.gitignore` | What git leaves out: `.env`, `node_modules/`, `.chapterjs/` and `data/`, the data of your stores. |
| `package.json` | The identity of your project: its name, its dependencies, and its scripts (`dev`, `build`, `start`, `typecheck`). |
| `tsconfig.json` | The settings of TypeScript. It only points to `.chapterjs/`, where the real settings are; leave it as it is. |

`chapterjs` is the only dependency of your bot. `typescript` and `@types/node` are development dependencies: they check your code in the editor and before a build, and are not needed to run the bot.

## Your files, your order

As a project grows, `src/commands/` fills up. Since the framework reads what files export and not where they are, sort them your way:

**src**

**fun**

**dice.ts**

**ping.ts**

**moderation**

**shared.ts**

**warn.ts**

* **A folder is only a folder.** `src/fun/dice.ts` declares `/dice` as well as `src/commands/dice.ts` would. Discord never sees your folders.
* **A file that declares nothing is yours.** `shared.ts` holds code several files share; import it like any file.
* **A file may declare several things.** `warn.ts` can hold the `/warn` command, the button it shows and the event that logs it, each exported under its own name.

A subcommand is a matter of `name`, not of folder: `name: 'mod warn'` is `/mod warn`, wherever the file is. That is used later for commands like `/mod ban`.

## Recap

* What a file exports says what it is: `command({ name: 'ping' })` is `/ping`, and nothing registers it.
* Every file imports its functions from `chapterjs`, and each one knows what to expect from what you give it.
* `.chapterjs/` holds the generated types; your editor reads them; `chapterjs sync` rewrites them.
* Save a file and the bot uses it; a broken file keeps its last working version.
* Folders and file names are yours to organise with: the framework reads what files export.

> [card] [Your first command](https://www.chapterjs.org/tutorial/first-command.md)
>
> Write /dice from scratch, and see what the framework checks for you.

> [card] [Guide: Project structure](https://www.chapterjs.org/setup/project-structure.md)
>
> Every file and folder, in short.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.