decompile-ai
decompile-ai is a backend service for automated binary analysis. It accepts uploaded binaries, runs them through multiple analysis engines (IDA Pro 5.0, IDA Pro 6.6, Ghidra) and DiE inside Docker containers, then provides AI-powered chat over the decompiled code using Ollama and a RAG pipeline backed by pgvector embeddings.
Tech Stack
| Component | Technology |
|---|---|
| Language | Java 25 |
| Framework | Spring Boot 4.0.6 |
| Build | Maven (wrapper included) |
| Database | PostgreSQL with pgvector extension |
| Migrations | Flyway |
| Message Broker | RabbitMQ |
| Module Boundaries | Spring Modulith |
| AI / Chat | Spring AI + Ollama |
| Container Mgmt | docker-java |
| Code Formatting | Spotless (Google Java Format) |
| Test DB | H2 (in-memory) |
Architecture
┌─────────────────────────────────────────────────────┐
│ REST API Layer │
│ Workspace / Project / Binary / Analysis / Jobs / AI │
└─────────────┬───────────────────────────────────────┘
│
┌─────────────▼───────────────────────────────────────┐
│ Service Layer │
│ ┌──────────┐ ┌──────────┐ ┌───────┐ ┌──────────┐ │
│ │ Workspace│ │ Analysis │ │ Engine│ │ AI │ │
│ │ Service │ │ Service │ │Service│ │ Service │ │
│ └──────────┘ └──────────┘ └───────┘ └──────────┘ │
│ ┌──────────┐ ┌──────────┐ ┌────────────────────┐ │
│ │ DiE │ │ Docker │ │ Job (Async Queue) │ │
│ │ Service │ │ Service │ │ ┌────────────────┐ │ │
│ └──────────┘ └──────────┘ │ │ RabbitMQ Pub/Sub│ │ │
│ │ └────────────────┘ │ │
└─────────────┬───────────────└────────────────────┘ │
│
┌─────────────▼───────────────────────────────────────┐
│ Infrastructure │
│ PostgreSQL + pgvector | RabbitMQ | Ollama │
│ Docker Engines: IDA5 | IDA66 | Ghidra | DiE │
└─────────────────────────────────────────────────────┘
Module Boundaries (Spring Modulith)
Each module declares its allowed dependencies through package-info.java:
workspace— CRUD for workspaces, projects, and uploaded binaries. PublishesBinaryUploadedEvent.analysis— Stores and queries static analysis results (functions, xrefs, labels, segments, strings, structs, enums, imports, libraries). Listens forStaticAnalysisRequestedEvent, publishesStaticAnalysisCompletedEvent.engine— Manages analysis engines (IDA 5, IDA 66, Ghidra) running in Docker containers. Produces standardizedAnalysisResultoutput.die— Runs DiE (Detect It Easy) inside a Docker container for file type detection and packer identification.docker— Low-level Docker container lifecycle management viadocker-java.job— Async job queue: creates, dispatches, executes, and tracks jobs via RabbitMQ. Job types:ANALYZE_FILE,STATIC_ANALYSIS,GENERATE_EMBEDDINGS.ai— AI-powered chat (SSE streaming) with RAG over decompiled code. Uses Spring AI + Ollama for chat and embedding generation. Exposes tool functions for the LLM to query analysis data.common— Shared configuration, exceptions (NotFoundException,ConflictException), and global error handling.
Job Lifecycle
ENQUEUED → STARTED → IN_PROGRESS → COMPLETED
↘ → FAILED
→ CANCELED
Async Flow (Upload → Analysis → Chat)
1. Upload binary → BinaryUploadedEvent
2. Job: ANALYZE_FILE → DiE detection + engine analysis (IDA5/IDA66/Ghidra)
3. Job: STATIC_ANALYSIS → Parse engine output → store functions/xrefs/labels/etc.
4. Job: GENERATE_EMBEDDINGS → Chunk decompiled code → generate pgvector embeddings
5. Chat session → RAG retrieval → Ollama streaming response with tool calls
Prerequisites
- Java 25
- PostgreSQL with pgvector extension
- RabbitMQ
- Ollama (with models pulled: e.g.
gemma4:12b,qwen3-embedding:latest) - Docker (with access to
/var/run/docker.sockfrom within the app container)
Getting Started
1. Clone and Configure
git clone <repo-url>
cd decompile-ai/backend
cp .env.example .env # edit as needed
2. Start Infrastructure
docker compose up -d postgres rabbitmq
This starts PostgreSQL (with pgvector) and RabbitMQ. Healthchecks ensure they're ready before the backend starts.
3. Create the Database
CREATE DATABASE decompile_ai;
CREATE EXTENSION vector;
Or let Flyway handle schema creation on first run (the vector extension must be installed manually or via superuser).
4. Pull Ollama Models
ollama pull gemma4:12b
ollama pull qwen3-embedding:latest
5. Run the Application
# Development
./mvnw spring-boot:run
# Or with Docker Compose (full stack)
docker compose up -d
The API will be available at http://localhost:8080.
Swagger UI is available at http://localhost:8080/swagger-ui.html.
Build Commands
./mvnw compile # Compile
./mvnw test # Run tests
./mvnw test -Dtest=ChatServiceTest # Run a specific test class
./mvnw package -DskipTests # Package as JAR
./mvnw spotless:apply # Format code (Google Java Format)
./mvnw spotless:check # Check formatting (CI)
Configuration
Configuration is in src/main/resources/application.yml and .env.
Key Settings
| Property | Default | Description |
|---|---|---|
app.storage.upload-dir |
./uploads/binaries |
Uploaded binary storage |
app.docker.enabled |
true |
Enable Docker container management |
app.die.image |
decompile-ai/diec:latest |
DiE Docker image |
app.die.timeout-seconds |
60 |
DiE analysis timeout |
app.engines.ida5.image |
decompile-ai/ida5:latest |
IDA Pro 5.0 image |
app.engines.ida5.timeout-seconds |
300 |
IDA 5 analysis timeout |
app.engines.ida66.image |
decompile-ai/ida66:latest |
IDA Pro 6.6 image |
app.engines.ida66.timeout-seconds |
300 |
IDA 66 analysis timeout |
app.engines.ghidra.image |
decompile-ai/ghidra:latest |
Ghidra image |
app.engines.ghidra.timeout-seconds |
600 |
Ghidra analysis timeout |
app.ai.default-chat-provider |
ollama |
Chat provider (ollama) |
app.ai.embedding.dimension |
4096 |
Embedding vector dimension |
app.ai.embedding.chunk-max-chars |
3000 |
Max chars per embedding chunk |
app.ai.embedding.batch-size |
20 |
Embedding generation batch size |
app.ai.rag.top-k |
5 |
RAG top-K results |
app.ai.rag.similarity-threshold |
0.6 |
Minimum similarity score |
app.ai.rag.max-context-tokens |
8000 |
Max context tokens for RAG |
app.ai.chat.max-history-messages |
20 |
Max chat history messages |
spring.servlet.multipart.max-file-size |
500MB |
Max upload size |
Environment Variables
| Variable | Default | Description |
|---|---|---|
AI_DEFAULT_CHAT_PROVIDER |
ollama |
Chat provider |
AI_CHAT_MODEL_OLLAMA |
gemma4:12b |
Ollama chat model |
AI_EMBEDDING_MODEL |
qwen3-embedding:latest |
Ollama embedding model |
AI_EMBEDDING_DIMENSION |
4096 |
Embedding dimension |
API Endpoints
A complete, interactive API reference is available via Swagger UI when the application is running:
http://localhost:8080/swagger-ui.html
Module Overview
| Module | Base Path | Description |
|---|---|---|
| Workspaces | /api/workspaces |
Workspace CRUD (top-level grouping) |
| Projects | /api/workspaces/{id}/projects |
Project CRUD (nested under workspaces) |
| Binaries | /api/projects/{id}/binaries |
Binary upload, download, and management |
| Analysis | /api/binaries/{id}/analysis |
Static analysis results (functions, xrefs, labels, strings, structs, enums, imports, libraries, segments) |
| Jobs | /api/jobs |
Async job queue — list, filter, get status, cancel |
| AI Chat | /api/chat/sessions |
Chat sessions and SSE streaming messages |
| Engines | /api/engines |
Available analysis engines |
AI Chat Features
- Streaming responses via Server-Sent Events (SSE)
- Tool calling — the LLM can query functions, xrefs, labels, strings, structs, imports, and more in real time
- Mutation suggestions — the AI can propose renames, type changes, and comments; mutations can be applied via the API
- RAG pipeline — decompiled code is chunked, embedded via Ollama, stored in pgvector, and retrieved at query time for context-aware responses
- Chat history — full conversation history is persisted and included in context (up to
max-history-messages)
Stream Event Types
The SSE stream emits a sealed hierarchy of events:
chunk— text delta from the LLMthinking— reasoning tokenstool_call_start/tool_call_end— tool invocation boundariesmutation_suggested/mutation_applied— rename/type/comment changestitle_generated— auto-generated session titledone— stream completeerror— error details
Docker Images
The project includes Dockerfiles for the analysis engines:
| Image | Base | Engine |
|---|---|---|
Dockerfile |
eclipse-temurin:25-jre-alpine |
Main app (multi-stage) |
Dockerfile.die |
ubuntu:24.04 |
DiE v3.21 |
engines/ida5/Dockerfile.ida5 |
debian:bullseye-slim |
IDA Pro 5.0 + Wine 32-bit |
engines/ida66/Dockerfile.ida66 |
debian:bookworm-slim |
IDA Pro 6.6 + Wine 32-bit + Python 2.7 |
engines/ghidra/Dockerfile |
alpine:latest |
Ghidra (placeholder) |
Build engine images before running the full stack:
docker build -t decompile-ai/diec:latest -f Dockerfile.die .
docker build -t decompile-ai/ida5:latest engines/ida5/
docker build -t decompile-ai/ida66:latest engines/ida66/
docker build -t decompile-ai/ghidra:latest engines/ghidra/
Database Migrations
Managed by Flyway in src/main/resources/db/migration/. Migrations are numbered sequentially (V001__... through V024__...) and cover all schema objects including pgvector indexes for embedding similarity search.
Testing
./mvnw test # All tests
./mvnw test -Dtest=*IntegrationTest # Integration tests only
./mvnw test -Dtest=*Test # Unit tests only
Tests use:
- JUnit 5 + Mockito for unit tests (
@ExtendWith(MockitoExtension.class)) - Spring Boot Test + H2 + MockMvc for integration tests (
@SpringBootTest,@ActiveProfiles("test")) - Spring Modulith Test for architecture verification (
ModulithArchitectureTest)
Project Structure
src/main/java/ai/decompile/
├── DecompileAiApplication.java # Entry point
├── WebConfig.java # CORS configuration
├── common/ # Shared utilities, exceptions, error handling
├── workspace/ # Workspace → Project → Binary CRUD
├── analysis/ # Static analysis results (functions, xrefs, labels, etc.)
├── engine/ # Analysis engines (IDA5, IDA66, Ghidra)
├── die/ # DiE file type detection
├── docker/ # Docker container management
├── job/ # Async job queue (RabbitMQ)
└── ai/ # AI chat + RAG embeddings (Spring AI + Ollama)
└── tools/ # LLM tool functions for querying analysis data
Coding Conventions
See AGENTS.md for the full style guide. Key highlights:
- Null checks:
Objects.isNull()/Objects.nonNull()— never raw== null - Braces: Always required, even for single-line
ifbodies - Type inference:
varfor local variables when type is obvious from RHS - DI: Constructor injection via Lombok
@RequiredArgsConstructor - Transactions:
@Transactionalon writes,@Transactional(readOnly = true)on reads - Logging: Lombok
@Log4j2with parameterized messages - Formatting: Google Java Format via Spotless (
./mvnw spotless:apply)
License
MIT