Step 0 — What you need before starting
Check these three things. Do not skip this section.
- Java (JDK 21 or newer) installed. Open a terminal (Windows: press the Start button, type
cmd, press Enter. macOS: press Cmd+Space, typeTerminal, press Enter. Linux: press Ctrl+Alt+T). Typejava -versionand press Enter. If you see a number that is 21 or higher, you are fine. If you see "command not found" or a smaller number, download a JDK from Adoptium (adoptium.net), install it, and reopen the terminal. - CT Client v4.3.0 or later installed and working. If you have not done that yet, follow the beginner guide first and come back.
- A text editor. Notepad on Windows, TextEdit on macOS, or any editor. VS Code is nice but not required.
Step 1 — Create the project folder
We will make a folder named ct-example-mod in your home directory. Your home directory is the folder with your name: C:\Users\yourname on Windows, /Users/yourname on macOS, /home/yourname on Linux.
Pick the line for your system, paste it into the terminal, press Enter:
Windows (cmd):
mkdir %USERPROFILE%\ct-example-mod
cd %USERPROFILE%\ct-example-mod
macOS:
mkdir -p ~/ct-example-mod/src/example
cd ~/ct-example-mod
Linux:
mkdir -p ~/ct-example-mod/src/example
cd ~/ct-example-mod
Now create the Java source folder too (macOS and Linux already did this above):
Windows (cmd):
mkdir src\example
macOS and Linux:
mkdir -p src/example
When this step is done, your folder looks like this:
ct-example-mod/
src/
example/ (empty for now)
ct-example-mod folder, and jump to Step 4.Step 2 — Write ct.mod.json (the mod's ID card)
Every CT mod must contain a file named exactly ct.mod.json. CT Loader reads this file to learn your mod's name, version, entrypoint, and dependencies. Create the file in the project folder and paste this exact content:
{
"schemaVersion": 1,
"id": "example",
"name": "Example Mod",
"version": "1.0.0",
"entrypoints": ["example.ExampleMod"],
"depends": []
}
What every line means:
| Field | What to type | Rules |
|---|---|---|
| schemaVersion | 1 | Always 1 today. Do not change it. |
| id | A short unique name, here example | Lowercase letters, digits, _ or - only. No spaces. Must be unique among installed mods. |
| name | A friendly name, here Example Mod | Shown in messages. Anything readable. |
| version | Your mod version, here 1.0.0 | Any text, but keep the 1.2.3 habit. |
| entrypoints | List of Java class names | Full package path, e.g. example.ExampleMod. At least one is needed. |
| depends | List of other CT mod ids | Leave empty [] for your first mod. |
Save the file with the name ct.mod.json — all lowercase, no .txt at the end — inside the ct-example-mod folder (next to src, not inside it).
Prefer not to type it? Download ct.mod.json directly and put it in the folder.
Step 3 — Write the Java entrypoint (the mod's engine)
Create a new file inside the src/example folder, name it exactly ExampleMod.java, and paste this:
package example;
import com.ct.module.ctloader.CTMod;
import com.ct.module.ctloader.CTModContext;
public final class ExampleMod implements CTMod {
@Override
public void onInitialize(CTModContext context) {
context.log("Example Mod initialized");
context.log("Game directory: " + context.gameDirectory());
context.log("Mods directory: " + context.modsDirectory());
context.log("Mod id: " + context.metadata().id());
context.log("Mod version: " + context.metadata().version());
}
}
Plain-language explanation of what you just wrote:
package example;— says this class lives in theexamplepackage. This must match the foldersrc/exampleand the start of the entrypoint nameexample.ExampleModinct.mod.json. Change all three together or nothing.implements CTMod— tells CT Loader this class is a mod entrypoint. Required.onInitialize(CTModContext context)— the method CT Loader calls when the game starts. Everything your mod does at startup begins here.context.log(...)— prints a line into the launcher console, prefixed with your mod id.context.metadata(),context.gameDirectory(),context.modsDirectory()— read your mod's own information and the folders it runs in.
public and must have the exact name from ct.mod.json. A typo here means CT stops the launch with an error naming your mod.Step 4 — Compile the Java class
Compiling turns your text file into a file computers run. Stay in the ct-example-mod folder in the terminal and run the line for your system:
Windows (cmd):
javac -cp ct-module-ctloader-4.3.0.jar -d classes src\example\ExampleMod.java
macOS and Linux:
javac -cp ct-module-ctloader-4.3.0.jar -d classes src/example/ExampleMod.java
What happens: a new folder named classes appears, containing example/ExampleMod.class. No news is good news — javac prints nothing when it succeeds. If you see errors, re-check Step 3 for typos, especially capital letters.
The -cp part points javac at the CT Loader module jar, which contains CTMod and CTModContext. Download it from the module page and put it in the ct-example-mod folder (or adjust the path to where it is). At runtime the launcher puts the module jar on the game classpath itself, so the flag is only for compiling.
Step 5 — Package everything into the mod JAR
The mod JAR is a zip file with a fixed layout. It needs exactly two things at the top level: the compiled class folder example/ and the ct.mod.json file. Run:
Windows (cmd):
jar --create --file ct-example-mod-1.0.0.jar -C classes . -C . ct.mod.json
macOS and Linux:
jar --create --file ct-example-mod-1.0.0.jar -C classes . -C . ct.mod.json
If jar is "not found", it ships with the JDK you installed in Step 0 — reopen the terminal so the PATH refreshes.
The finished project folder now looks like this:
ct-example-mod/
src/
example/
ExampleMod.java the source you wrote in Step 3
classes/
example/
ExampleMod.class the compiled file from Step 4
ct.mod.json the metadata from Step 2
ct-example-mod-1.0.0.jar the finished mod from this step
Step 6 — Install the mod into the mods folder
Copy ct-example-mod-1.0.0.jar into the mods folder of the game directory. With default CT settings that folder is hidden, so use the terminal:
Windows (cmd):
explorer %USERPROFILE%\.ct-client\game\mods
(the folder may be empty or missing — CT creates it on launch;
create it yourself with: mkdir %USERPROFILE%\.ct-client\game\mods)
copy ct-example-mod-1.0.0.jar %USERPROFILE%\.ct-client\game\mods\
macOS:
mkdir -p ~/.ct-client/game/mods
cp ct-example-mod-1.0.0.jar ~/.ct-client/game/mods/
Linux:
mkdir -p ~/.ct-client/game/mods
cp ct-example-mod-1.0.0.jar ~/.ct-client/game/mods/
More ways to open that folder (Finder, Explorer, file manager) are on the mods folder page. If you changed the game directory in CT settings, the mods folder lives under that directory instead.
Step 7 — Launch and verify it works
Start CT Client, pick your version, and press Launch. In the console you should see, before the game starts:
[example] Example Mod initialized
[example] Game directory: /Users/you/.ct-client/game
[example] Mods directory: /Users/you/.ct-client/game/mods
[example] Mod id: example
[example] Mod version: 1.0.0
Congratulations — that is a working CT mod. Change the log lines, re-run Steps 4, 5, and 6 (recompile, repackage, recopy), and launch again to see your changes.
If something goes wrong
| Symptom | Cause and fix |
|---|---|
| Launch stops and names your mod | ct.mod.json is malformed. Check commas and quotes against Step 2 exactly. |
| Error mentions a duplicate id | Another installed mod already uses example. Change id in ct.mod.json to something unique. |
| Error mentions a missing dependency | Your depends lists a mod id that is not installed. Install it or remove it from the list. |
| Error mentions the entrypoint class | The name in ct.mod.json does not match the compiled class, or the class is not public, or it does not implement CTMod. |
No [example] lines in the console | The JAR is in the wrong mods folder, or the JAR layout is wrong — ct.mod.json must be at the top level of the JAR, next to the example/ folder, not inside classes/. |
| Nothing loads at all | The mods folder must be inside the game directory CT is actually using. Check the game directory in CT settings. |
Where to go next
You now know the full loop: edit → compile → package → copy → launch. To grow from here: add more entrypoint classes and list them in entrypoints; publish two mods and make one depend on the other to watch the load order; read the full mod format reference and the CT mod loader API. Remember the one rule that matters: a mod is ordinary executable Java — only ever install JARs you trust, and only share yours with people who trust you.