Thank you for your interest in contributing! This guide will help you get started.
- Java 21+ - Eclipse Temurin recommended
- Git - For version control
- IDE - IntelliJ IDEA recommended (has excellent Minecraft modding support)
git clone https://github.com/anthropics/opencode-minecraft.git
cd opencode-minecraft
./gradlew build- Open the project folder in IntelliJ
- Import as Gradle project when prompted
- Wait for indexing to complete
- Run
./gradlew genSourcesto generate Minecraft sources for navigation
- Install the "Extension Pack for Java" extension
- Open the project folder
- Run
./gradlew genSourcesfor source navigation
# Launch Minecraft with the mod loaded
./gradlew runClientThis launches Minecraft with hot-reload support. The game will connect to http://localhost:4096 by default.
src/main/java/com/opencode/minecraft/
├── OpenCodeMod.java # Mod entry point, initialization
├── client/
│ ├── OpenCodeClient.java # Main coordinator for HTTP and events
│ ├── http/
│ │ ├── OpenCodeHttpClient.java # REST API client
│ │ └── SseEvent.java # SSE event data model
│ └── session/
│ ├── SessionManager.java # Session lifecycle management
│ ├── SessionInfo.java # Session data model
│ └── SessionStatus.java # Status enum (IDLE, BUSY, etc.)
├── game/
│ ├── PauseController.java # Game pause logic (CRITICAL)
│ ├── MessageRenderer.java # Chat message rendering
│ └── PauseOverlay.java # Visual overlay when paused
├── command/
│ └── OpenCodeCommand.java # /oc command handlers
├── config/
│ ├── ModConfig.java # Configuration data model
│ └── ConfigManager.java # Config load/save
├── mixin/
│ ├── IntegratedServerMixin.java # Server tick control
│ ├── KeyboardInputMixin.java # Input blocking when paused
│ ├── InGameHudMixin.java # HUD overlay hook
│ └── MinecraftClientMixin.java # Client lifecycle hooks
└── util/
└── MarkdownToMinecraft.java # Markdown to Minecraft formatting
- Use Java 21 features where appropriate
- Follow existing code patterns in the project
- Keep methods focused and reasonably sized
- Use meaningful variable and method names
- 4-space indentation (no tabs)
- Opening braces on same line
- Max line length: 120 characters
- Use
this.prefix for instance fields
- Use Javadoc for public methods
- Add inline comments for complex logic
- Keep comments up-to-date with code changes
Mixins are how we hook into Minecraft's code. They're powerful but require care.
- Minimize scope - Only inject what you need
- Use unique prefixes - All injected fields/methods use
opencode$prefix - Handle failures gracefully - Minecraft updates can break mixins
- Test thoroughly - Mixins can cause subtle bugs
| Mixin | Target | Purpose |
|---|---|---|
IntegratedServerMixin |
IntegratedServer |
Cancels server ticks when paused |
KeyboardInputMixin |
KeyboardInput |
Blocks player input when paused |
InGameHudMixin |
InGameHud |
Renders pause overlay |
MinecraftClientMixin |
MinecraftClient |
Client lifecycle hooks |
- Create the mixin class in
com.opencode.minecraft.mixin - Add it to
opencode.mixins.json - Use
@Injectwith appropriate timing (HEAD,TAIL,RETURN) - Prefix all injected names with
opencode$
Example:
@Mixin(SomeMinecraftClass.class)
public class SomeMinecraftClassMixin {
@Inject(method = "someMethod", at = @At("HEAD"), cancellable = true)
private void opencode$onSomeMethod(CallbackInfo ci) {
if (shouldCancel()) {
ci.cancel();
}
}
}The mod communicates with OpenCode via:
| Endpoint | Method | Purpose |
|---|---|---|
/global/health |
GET | Health check |
/global/event |
GET | SSE event stream |
/session |
GET | List sessions |
/session |
POST | Create session |
/session/{id} |
GET | Get session details |
/session/{id}/message |
POST | Send prompt |
/session/{id}/abort |
POST | Cancel generation |
Events arrive at /global/event. Key event types:
session.status- Session state changes (idle/busy)message.part.updated- Content updates (withdeltafor tokens)message.created- New message startedserver.heartbeat- Keep-alive
- Network operations: Background thread (HttpClient executor)
- Game state changes: Main thread via
MinecraftClient.execute() - Always dispatch to main thread before touching Minecraft state
- Run
./gradlew runClient - Create a single player world
- Start OpenCode:
opencode serve - Test commands:
/oc status,/oc session new,/oc hello - Verify pause/resume behavior
- Connection and reconnection
- Session create/list/switch
- Prompt sending and response display
- Pause when idle, resume when generating
- Cancel with
/oc cancel - Config changes persist
- Run
./gradlew build- ensure it compiles - Test your changes manually in-game
- Update documentation if needed
- Keep commits focused and well-described
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-feature - Make your changes
- Push to your fork
- Open a Pull Request with:
- Clear description of changes
- Any related issues
- Testing performed
- Keep PRs focused on one feature/fix
- Include screenshots/GIFs for UI changes
- Respond to review feedback promptly
- Squash commits if requested
When opening an issue, please include:
- Minecraft version
- Mod version
- Steps to reproduce
- Expected vs actual behavior
- Relevant logs (from
.minecraft/logs/latest.log)
- Open a GitHub issue for bugs or feature requests
- Check existing issues before creating new ones
Thank you for contributing!