Skip to main content

Setup development environment

Pre-requisites​

The Lasers-Enigma family can be set up as a single workspace — you clone one master repo (le-workspace) and a bootstrap script clones the six sibling repos side by side, enables the git hooks, and syncs the shared AI tooling — or repo by repo: every repo is also installable on its own (see Working from a single repo). Before starting, make sure you have:

  • Git — download and install. On Windows, this also installs Git Bash, the POSIX shell required to run bootstrap.sh (PowerShell and cmd cannot run it; WSL works too).

  • A GitLab SSH key (required) — bootstrap.sh clones over SSH ([email protected]:â€Ļ), so an SSH key is mandatory, not just convenient. Generate one and add the public key to GitLab → Preferences → SSH Keys. On the first clone, accept the gitlab.com host key when prompted.

  • The toolchain(s) for the repos you'll actually work on — install only what you need:

    RepoToolchain
    lasersenigma (the plugin)IntelliJ + Java Temurin 21 (IntelliJ install guide)
    le-play-server-utils (LEPSU)Java Temurin 21 (Maven comes with the checked-in wrapper ./mvnw)
    le-room-organizerGo â‰Ĩ 1.23 + Node â‰Ĩ 20
    le-agent, le-mcpPython + uv

    Always build with the wrapper checked into the repo — ./gradlew (gradlew.bat) and ./mvnw (mvnw.cmd) — never with a globally installed Gradle or Maven, even if you have one: the wrapper pins the build-tool version for everyone.

    This table is a summary: each repo's README.md (Requirements section) is the source of truth for its toolchain — that is what /onboarding reads. Node â‰Ĩ 20 is also used by the GitLab and Discord MCP servers (launched via npx) and by bootstrap.sh.

Clone the workspace​

The whole family is bootstrapped from the le-workspace master repo. From a parent directory of your choice:

git clone [email protected]:lasersenigma/le-workspace.git
cd le-workspace
./bootstrap.sh # Windows: run from Git Bash, not PowerShell

bootstrap.sh clones the six sibling repos side by side under le-workspace/, enables the versioned commit-hygiene hooks in each (core.hooksPath .githooks + the per-repo hooks.requireIssueRef policy — false for le-agent / le-mcp, true elsewhere), and runs the initial shared-tooling sync. It is safe to re-run: an already-cloned repo is left untouched (only hooks + sync are re-applied).

In Claude Code you can skip the manual ./bootstrap.sh: /onboarding runs it for you (in the background, idempotent) when the sibling repos are missing, then continues with the checks below.

Then check your setup: ./workspace-doctor.sh audits the machine, every clone, the external MCP servers and the synced tooling, read-only — or, in Claude Code, run /onboarding, which runs the same checks, reads each repo's own requirements, probes the MCP servers, applies the safe setup steps for you (git config, sample configs copied, dependencies installed, builds), asks only for real choices, pauses on each secret you have to set yourself, and can run the long steps such as setupDevEnvironment in the background on request (/onboarding quick skips the explanations). The doctor scripts never change anything; the command never touches a file tracked by git and never writes a secret.

DirectoryRoleStack
lasersenigma/The pluginJava / Gradle / Paper
wiki/Developer & player documentation — the source of truth under Develop/Markdown
le-play-server-utils/LEPSU: play-server Paper plugin (portals, puzzle rooms, reviews, hints, lobby)Java / Maven / Paper
le-room-organizer/Standalone tool to reorganize rooms across portalsGo + React
le-mcp/MCP server exposing the wiki docs as LLM toolsPython / uv
le-agent/LangGraph agent (Gemini + le-mcp) for the LEPSU /puzzle doc commandPython / uv

The six repos are gitignored inside le-workspace/ (each is a standalone clone with its own remote — not a git submodule). Commit and push from inside the relevant directory.

With partial access (an external contributor typically cannot reach every repo), bootstrap.sh warns, skips the repo it cannot clone and carries on with the others — nothing to do by hand; /onboarding reports that repo as optional.

After cloning, each repo is on its default main branch (lasersenigma targets Minecraft 1.19.4 → 1.21.x — the only development branch).

Open the plugin in IntelliJ​

Open the lasersenigma/ directory (under le-workspace/) as the IntelliJ project. The sections below (setupDevEnvironment, the run/ servers, the run configurations) all operate inside it.

Commit-hygiene git hooks (already enabled by bootstrap)​

bootstrap.sh has already enabled the versioned commit-msg hook in every clone — it strips any AI-credit trailer, validates the Conventional Commits subject and its (#<issue>) reference, and blocks GitLab auto-close keywords. You only need to act if you cloned a repo outside bootstrap.sh; then enable it manually, once per clone:

git config core.hooksPath .githooks
## le-agent / le-mcp only require the issue reference when the work tracks an issue:
git config hooks.requireIssueRef false

This works from any shell or IDE — PowerShell 7, cmd, Git-Bash, IntelliJ, VS Code — because git runs the hook through its own bundled sh, never your shell. Each plugin repo's pre-commit also runs check-lang-encoding.py, which refuses a commit whose text was destroyed rather than edited — the signature a UTF-8 file leaves when a tool reads it as the machine's ANSI codepage and writes it back. It needs Python on your PATH; without it the hook says so and steps aside, and CI enforces the same check anyway. Prevention is the other half: run any script that rewrites project files in UTF-8 mode (PYTHONUTF8=1, or python -X utf8), which AGENTS.md now requires. IntelliJ's Darkyen Time Tracker keeps working: a prepare-commit-msg shim chains to its local hook. In a genuine emergency you can skip the checks with git commit --no-verify.

Working from a single repo (without the workspace)​

Every repo of the family is self-sufficient: you can contribute to the plugin, LEPSU, the room organizer, le-agent or le-mcp without ever cloning le-workspace. Each clone ships its own AGENTS.md, .githooks/, .mcp.json, the AI commands and skills, and the doctor.sh diagnosis script.

git clone [email protected]:lasersenigma/lasersenigma.git # or the https URL — SSH is only required to push
cd lasersenigma
git config core.hooksPath .githooks # enable the commit checker (see above)
sh doctor.sh # read-only: machine + this clone, with the fix for each finding

Then follow the repo's README.md — its Requirements section lists the toolchain, and its setup sections the steps to run — or let /onboarding in Claude Code do that walk-through for you, in the same way as in the workspace.

What the workspace adds, if you want it later: the wiki on disk (the issue / triage skills read the label rules from ../wiki), the sibling repos (/release needs them), the patched Discord MCP server (/discord-triage, maintainers), and sync-tooling.sh to edit the shared tooling. To switch: clone le-workspace, move your existing clone inside it, run ./bootstrap.sh — an already-cloned repo is left untouched.

Editing the shared AI tooling​

The .claude/ commands and skills are synced (tracked) from le-workspace into every child and carry an AUTO-SYNCED from le-workspace header — never hand-edit a synced file inside a child. Edit the canonical copy in le-workspace/.claude/ and re-run ./sync-tooling.sh <child> (or --all). sync-manifest.txt lists what is synced, by type (command / skill / hook / script). Fragments (.claude/fragments/) are a build input: edited once canonically and inlined into the commands at sync time so each shipped command is self-contained (the runtime doesn't transclude links) — they are not shipped as standalone files. The hook type distributes the canonical commit-msg git hook verbatim into every child except the wiki (its own lighter variant; le-workspace's pre-commit cross-repo guard is repo-local, not synced). The script type distributes doctor.sh and check-lang-encoding.py verbatim to every child's root (wiki included), checked byte-exact — each child pins *.sh and *.py to LF in its .gitattributes for that reason. The le-workspace .githooks/pre-commit guard whitelists .claude/{commands,fragments,skills}/. Run ./sync-tooling.sh --check --all before pushing a tooling change to catch any drift — from the main clone, not from a git worktree (no sibling repo sits beside a worktree, so the script now stops with an error instead of reporting a clean state over zero children). See AI Prompts and Skills for the full tooling reference.

Check that the project compiles​

Run Gradle (the wrapper is included in the project, no need to install Gradle):

./gradlew clean build

You can also do it from IntelliJ's Gradle tool window.

The ./gradlew examples on this page assume a POSIX shell (Git Bash on Windows). In Windows PowerShell or cmd, use the batch wrapper instead: .\gradlew.bat clean build.

Prepare local game servers​

The project uses local Paper game servers to test the plugin. The standard setup creates 4 servers under run/:

DirectoryPurposeMC version
run/le-play/Mirror of the play server (untouched)Latest (from play server)
run/latest/Latest MC version testingLatest stable
run/1.20.4/MC 1.20.4 testing1.20.4
run/1.19.4/Oldest supported version testing1.19.4

This method requires access to the Skytale Pterodactyl panel. If you don't have access, ask it on discord or see Manual setup instead.

1. Configure API tokens​

Some Gradle tasks require API tokens. These are stored in your personal Gradle properties file, outside the project directory, so they are never committed to git.

OSFile path
WindowsC:\Users\<your-username>\.gradle\gradle.properties
macOS/Users/<your-username>/.gradle/gradle.properties
Linux/home/<your-username>/.gradle/gradle.properties

Create the file if it doesn't exist, then add:

## Pterodactyl panel configuration (required for automated server setup)
## Generate API key from: Account → API Credentials in the Pterodactyl panel
## Create at: https://panel.skytale.fr/account/api
pterodactylPanelUrl=https://panel.skytale.fr/
pterodactylApiKey=ptlc_xxxxxxxxxxxxxxxxxxxx
pterodactylServerId=5bcf33bc

## Remote debug host (optional, for remote debug run config generation)
## Find (in address field in the sidebar) at: https://panel.skytale.fr/server/5bcf33bc
remoteDebugHost=<server-ip-address>
## remoteDebugPort=25566 (optional, defaults to 25566)

Fill the 2 fields pterodactylApiKey and remoteDebugHost with the appropriate values (instructions are in comments above).

âš ī¸ Never put tokens in the project's gradle.properties — it would be committed to the repository. These properties are shared across all Gradle projects on your machine (e.g. Lasers-Enigma, LEPSU).

If you don't have Pterodactyl access yet, contact us to get an account and the appropriate permissions. Then go to Account → API Credentials and create a new API key.

GitLab personal access token (for the GitLab MCP server)​

GitLab operations performed by the AI tooling (read issues and comments, create/edit issues, fetch Merge Request review comments) go through the GitLab MCP server (@zereight/mcp-gitlab). The server is already declared in the repo — .mcp.json for Claude Code — so you only need to provide a token through the GITLAB_PERSONAL_ACCESS_TOKEN environment variable (this is independent of Pterodactyl access).

  1. Create a token with scope api at https://gitlab.com/-/user_settings/personal_access_tokens (read_api is enough for read-only use, but api is required to create or edit issues).

  2. Expose it as an environment variable:

    OSHow
    Windowssetx GITLAB_PERSONAL_ACCESS_TOKEN "glpat-xxxxxxxxxxxxxxxxxxxx" (new terminals only), or add it via System Properties → Environment Variables
    macOS / Linuxadd export GITLAB_PERSONAL_ACCESS_TOKEN="glpat-xxxxxxxxxxxxxxxxxxxx" to your shell profile (~/.zshrc, ~/.bashrc, â€Ļ)
  3. Restart your IDE / terminal so the MCP server picks up the variable.

âš ī¸ The token lives in your environment, never in the repo. .mcp.json only references the variable name, it doesn't contain the secret.

â„šī¸ GITLAB_TOOLSETS requirement — the committed .mcp.json sets the GITLAB_TOOLSETS env var on the MCP server (merge_requests,issues,repositories,branches,projects,labels,groups,users,ci,pipelines,variables). The variables and pipelines toolsets are required by the check-server-status skill and the release workflow (reading CI/CD variables, triggering/monitoring pipelines). An explicit GITLAB_TOOLSETS list replaces the server's defaults, and toolsets activated dynamically via discover_tools are not visible to an already-running agent session — so keep the toolsets in the static config; if you maintain a custom MCP setup, replicate this variable.

Discord bot token (for the Discord MCP server)​

The /discord-triage command reads the #suggestions / #bug-reports channels and posts replies and the Issues created marker through the Discord MCP server (mcp-discord), declared in .mcp.json like the GitLab one. It authenticates as a bot whose token you expose through the DISCORD_TOKEN environment variable. Only maintainers who run the triage need it — the server starts without a token and the other commands ignore it.

  1. Create the bot (once per Discord server — ask a maintainer if it already exists): on the Discord developer portal create an application, open its Bot tab, click Reset Token and copy the token (shown once).

  2. Enable the privileged intents the server's client requests at login, in the same Bot tab, under Privileged Gateway Intents: Message Content Intent (without it, message contents and embeds come back empty) and Server Members Intent. No Discord review is needed under 100 servers.

  3. Invite it with no server-wide permission: OAuth2 → URL Generator, scope bot, permissions left empty (permissions=0), open the generated URL and add the bot to the server. Then, in each of the two channels only (Edit channel → Permissions → add the bot), allow View Channel, Read Message History and Send Messages. The bot must not see or write anywhere else.

  4. Expose the token:

    OSHow
    Windowssetx DISCORD_TOKEN "xxxxxxxx.xxxxxx.xxxxxxxxxxxxxxxx" (new terminals only), or System Properties → Environment Variables
    macOS / Linuxadd export DISCORD_TOKEN="xxxxxxxx.xxxxxx.xxxxxxxxxxxxxxxx" to your shell profile
  5. Run ./bootstrap.sh (or re-run it) — the triage relies on two additions to mcp-discord, the full embed content + attachment URLs on read and embeds on send, which the published npm package does not have yet (upstream PR). There is nothing manual to do: bootstrap.sh clones our fork into le-workspace/mcp/mcp-discord/ (gitignored, like the sibling repos), builds it and links it globally, so the committed .mcp.json picks it up. That file deliberately holds no path (npx -y mcp-discord), because the very same file is synced into every child repo and has to resolve from any directory; npx looks at a global install before the registry. Removal of this interim wiring is tracked by issue #831.

  6. Restart your IDE / terminal so the MCP server picks up the variable.

âš ī¸ The bot token is a credential: it lives in your environment, never in the repo or in a commit. .mcp.json does not reference it at all — the server reads DISCORD_TOKEN from the process environment.

2. Configure plugin deployment​

Copy core/dev-example.properties to core/dev.properties and set:

## Automatically copy the built JAR to servers plugins on build
SKIP_COPY_JAR_TO_SERVER=false
## Comma-separated list of plugins directories (absolute or relative to project root)
SERVER_PLUGINS_DIRECTORIES=run/le-play/plugins,run/latest/plugins,run/1.20.4/plugins,run/1.19.4/plugins

This tells Gradle which servers to target for all development tasks.

âš ī¸ Keep defaults settings for setupDevEnvironment to work correctly. The run/ directories are automatically created and managed by the setup task, so you don't need to create them manually.

3. Run the setup​

A single command sets up everything:

./gradlew setupDevEnvironment

Or use the ⚙ Setup Dev Environment run configuration in IntelliJ.

This takes about 20 minutes (mostly downloading and server starts). It runs these tasks in order:

StepTaskDescription
1downloadServerArchiveDownloads a full server archive from the Pterodactyl panel
2cleanRunServersDeletes any existing run/ directories
3extractServerArchivesExtracts the archive into server directories (run/1.19.4/ is created empty)
4updatePaperJarsDownloads the latest Paper JAR for each server's MC version (except le-play)
5bootstrapEmptyServersLaunches empty servers once to generate config files (run/1.19.4/)
6cleanupServerRemoves unnecessary files from Pterodactyl-extracted servers (schematics, logs, temp files)
7patchServerConfigsPatches spigot.yml and config/paper-global.yml for local development. See details below
8configureLog4jCreates log4j2.xml with trace-level logging for the plugin
9updateLepsuDeploys le-play-server-utils: legacy version to 1.20.4, latest version to latest
10updateNoteBlockApiDeploys the NoteBlockAPI plugin to all servers (except le-play)
11updateSparkDownloads and deploys the latest spark profiler to all servers (except le-play). Can be skipped with -PskipUpdateSpark
12buildAndDeployBranchesBuilds LasersEnigma once and deploys the JAR to all servers (latest, 1.20.4, 1.19.4). le-play is left untouched
13verifyServersLaunches each server to verify it starts without errors

4. Generate remote debug config (optional)​

If you have set remoteDebugHost in ~/.gradle/gradle.properties:

./gradlew generateRemoteDebugConfig

This generates the 🔌 remote debug LE Play run configuration (git-ignored since it contains the server IP).

5. You're done!​

You can now use the IntelliJ run configurations to build and start any server. See Run configurations.

Manual setup (without Pterodactyl access)​

If you don't have access to the Pterodactyl panel (e.g. external contributors), you can set up servers from scratch. You don't need all four — pick the ones relevant to your work.

1. Create server directories​

## Latest Minecraft version
mkdir -p run/latest

## Older Minecraft versions (optional, to test 1.19.4-1.20.4 compatibility)
mkdir -p run/1.20.4
mkdir -p run/1.19.4

On Windows (PowerShell): New-Item -ItemType Directory -Path run/latest -Force

2. Configure plugin deployment​

Copy core/dev-example.properties to core/dev.properties and set:

SKIP_COPY_JAR_TO_SERVER=false
SERVER_PLUGINS_DIRECTORIES=run/latest/plugins

Adjust SERVER_PLUGINS_DIRECTORIES to match the servers you created (comma-separated for multiple).

3. Download Paper​

./gradlew updatePaperJars

This downloads the latest Paper build matching each server's MC version. For new empty directories, it detects the version from the directory name (e.g. 1.19.4) or defaults to the latest stable MC version.

Alternatively, download Paper manually from papermc.io and place the JAR as server.jar in your server directory.

4. Accept the EULA and first launch​

Each server needs a first launch to generate its configuration files:

  1. Create an eula.txt file in each server directory with the content eula=true
  2. Start each server once:
cd run/latest
java -jar server.jar nogui

Wait until you see Done! in the logs, then type stop in the console to shut it down. Repeat for each server directory.

5. Apply debug-friendly configuration​

./gradlew patchServerConfigs
./gradlew configureLog4j
  • patchServerConfigs sets max-tick-time to -1 in spigot.yml to prevent crashes when paused on a debugger breakpoint and sets proxy-protocol to false in config/paper-global.yml so the local server accepts direct connections without a proxy.
  • configureLog4j creates a log4j2.xml with trace-level logging for eu.lasersenigma and NonEuclideanSpaceBuilder.

6. You're done!​

You can now use the â–ļ latest run configuration in IntelliJ to build and start the server. See Run configurations.

Run configurations​

The project includes shared IntelliJ run configurations in the .run/ directory, automatically detected by IntelliJ:

NameTypeDescription
⚙ Setup Dev EnvironmentGradleRuns the full setupDevEnvironment task
â–ļ le-playJAR ApplicationBuilds the plugin, then starts run/le-play/server.jar
â–ļ latestJAR ApplicationBuilds the plugin, then starts run/latest/server.jar
â–ļ 1.20.4JAR ApplicationBuilds the plugin, then starts run/1.20.4/server.jar
â–ļ 1.19.4JAR ApplicationBuilds the plugin, then starts run/1.19.4/server.jar
🔌 remote debug LE PlayRemote DebugConnects to the play server for remote debugging (generated, git-ignored)

All server run configurations include:

  • A Before launch Gradle build task (builds and deploys the plugin automatically)
  • -Dlog4j.configurationFile=log4j2.xml for trace-level plugin logging
  • -Xms3G -Xmx3G memory allocation
  • nogui mode

Note: By default, all servers use the same port (25565). To run multiple servers simultaneously, change the server-port value in each server's server.properties file to a different port.

To create a custom run configuration manually, see the Debug documentation.

Advanced​

Re-setup a single server​

To re-run the full setup for a specific server only (without touching the others), use the -PserverFilter parameter:

./gradlew setupDevEnvironment "-PserverFilter=le-play"

Only the targeted server is deleted and re-extracted — other servers are left untouched. The filter supports comma-separated values (e.g. -PserverFilter=latest,1.20.4).

The filter also works with individual tasks:

./gradlew verifyServers "-PserverFilter=latest"
./gradlew updatePaperJars "-PserverFilter=1.19.4,1.20.4"

On Windows PowerShell, -P must be quoted: "-PserverFilter=1.20.4"

Run individual setup tasks​

Each task in the setupDevEnvironment chain can be run independently. This is useful when you need to re-apply a specific step without running the full setup:

./gradlew updatePaperJars # Re-download Paper JARs
./gradlew cleanupServer # Remove unnecessary files from extracted servers
./gradlew patchServerConfigs # Re-patch spigot.yml + paper-global.yml
./gradlew patchSpigotYml # Re-patch spigot.yml only
./gradlew patchProxyProtocol # Re-patch proxy-protocol in paper-global.yml (target value: -PproxyProtocol, default false)
./gradlew configureLog4j # Re-generate log4j2.xml
./gradlew updateLepsu # Re-deploy LEPSU
./gradlew updateNoteBlockApi # Re-deploy NoteBlockAPI
./gradlew updateSpark # Re-deploy spark profiler
./gradlew buildAndDeployBranches # Re-build and deploy LasersEnigma from branches
./gradlew verifyServers # Re-verify all servers start correctly

Server pack generation​

Additional tasks are available for generating a distributable server pack from the le-play server:

./gradlew cleanupServer "-PserverFilter=le-play" # Remove unnecessary files
./gradlew sanitizeServer "-PserverFilter=le-play" # Remove sensitive data (API keys, SSH keys, webhooks)
./gradlew createServerPackArchive # Create a .tar.gz archive of le-play
./gradlew generateServerPack # Full pipeline: setupDevEnvironment + sanitize + archive

generateServerPack is the single entry point that chains everything: it runs setupDevEnvironment (filtered to le-play, with spigot.yml and log4j patches skipped), then sanitizeServer, then createServerPackArchive.

Optional flags​

The following flags can be passed to setupDevEnvironment (or to individual tasks where relevant):

PropertyEffect
-PskipUpdateSparkSkips the spark profiler download and deployment
-PskipPatchSpigotYmlSkips the patchSpigotYml step inside patchServerConfigs (only patchProxyProtocol runs)
-PskipConfigureLog4jSkips the configureLog4j task entirely
-PproxyProtocol=true|falseTarget value for proxy-protocol in config/paper-global.yml (used by patchProxyProtocol, default false)

Example:

./gradlew setupDevEnvironment "-PskipUpdateSpark"

On Windows PowerShell, -P must be quoted: "-PskipUpdateSpark"

Plugin deployment configuration​

The core/dev.properties file controls which servers are targeted by build deployment and development tasks:

## Automatically copy the built JAR to server plugins on build
SKIP_COPY_JAR_TO_SERVER=false

## Comma-separated list of plugins directories (absolute or relative to project root)
SERVER_PLUGINS_DIRECTORIES=run/le-play/plugins,run/latest/plugins,run/1.20.4/plugins,run/1.19.4/plugins

You can also point to external servers:

SERVER_PLUGINS_DIRECTORIES=D:\\DEV\\Paper-1.21\\plugins

Note: setupDevEnvironment only operates on servers inside the project's run/ directory. External servers are used by other tasks (copyToServer, updatePaperJars, etc.) but are excluded from the automated setup.

Note: The legacy property SERVER_PLUGINS_DIRECTORY (singular) is still supported for backward compatibility and is merged with the list above.

How buildAndDeployBranches works​

buildAndDeployBranches builds LasersEnigma once (from the current working tree) and deploys the JAR to every configured server except the le-play production mirror. Since the plugin now supports every targeted Minecraft version from a single branch, there is no per-branch checkout anymore.

Verify the GitLab MCP server​

The GITLAB_PERSONAL_ACCESS_TOKEN environment variable is consumed by the GitLab MCP server, used by the AI tooling (the fix-mr-comments workflow, the create-issue / edit-issue / fetch-gitlab-issue / fetch-mr-comments skills) to talk to GitLab.

To verify it works, ask your assistant to run the MCP server's health_check and whoami tools — a healthy response reports authenticated: true and your GitLab username (/onboarding runs this probe for you, and tells a server that was not enabled yet apart from a bad token). If authentication fails, check that the variable is set (and that you restarted the IDE / terminal after setting it) and that the token has the api scope.

Verify the Discord MCP server​

The DISCORD_TOKEN environment variable is consumed by the Discord MCP server (mcp-discord), used only by the /discord-triage command.

To verify it works, ask your assistant to run the MCP server's discord_list_servers tool (/onboarding does it too, as an optional, maintainer-only check) — a healthy response lists the Lasers-Enigma server. An empty list or a "not logged in" error means the variable is missing (restart the IDE / terminal after setting it), the token was reset, or a privileged intent is disabled on the developer portal (login then fails with Used disallowed intents). A Missing Access error on discord_read_messages means the per-channel permissions of step 3 above are missing.

Pitfall: an MCP server's connection times out on Windows (npx startup)​

On Windows — especially with nvm4w and Node â‰Ĩ 24 — an MCP server launched through npx can fail to start with MCP server 'gitlab' connection timed out after 30000ms (same for discord), even though the token is valid. The committed config launches the servers on demand via npx -y <package>; in this setup the per-invocation resolution of npx (npm-managed .cmd/extensionless shims, stricter Node 24 process spawning) does not complete within the client's 30 s startup window. Warming the npx cache is not enough.

Fix: install the server globally so npx resolves it instantly instead of resolving it on every launch, then restart Claude Code / your IDE:

npm i -g @zereight/mcp-gitlab
npm i -g mcp-discord # or the patched fork build — see "Discord bot token" above

An elevated (admin) shell is not required. This keeps the committed .mcp.json unchanged and cross-platform — it is a local-machine fix only.

AI Assistant Configuration​

The project's canonical rule source is AGENTS.md at the project root. It defines architecture, conventions, layer structure, translation workflow, commit naming, and every other non-obvious rule.

The assistant supported today is Claude Code, whose thin entry-point CLAUDE.md at the project root points to AGENTS.md. To wire another provider, see Re-adding another AI provider.

Commands and skills​

In addition to the custom instructions, the project provides:

  • Commands under .claude/commands/ for multi-step workflows (onboarding, dev-issue, review, fix-mr-comments, release, design, deliver, finalize-series, epic, discord-triage) — canonical source, synced (tracked) from the le-workspace root. The fragments (reusable primitives the commands are built from) are a build input, inlined into the commands at sync time so each shipped command is self-contained — they are not shipped as standalone files (see Editing the shared AI tooling).
  • Claude Code skills under .claude/skills/ for atomic auto-triggered operations (translation staging/flush, version bump, branch+commit validation, CHANGELOG entry, log analysis, etc.).

See AI Prompts and Skills for the full reference and usage instructions.