<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Jarvis-ai-platform]]></title><description><![CDATA[building a local-first AI assistant with Spring Boot 4 and Spring AI 2.0.]]></description><link>https://jarvis-ai-platform.hashnode.dev</link><image><url>https://cdn.hashnode.com/uploads/logos/6a202d2a54e8a60fa0ff6c4d/c3f682b0-0090-469d-be47-2bf46b397a58.png</url><title>Jarvis-ai-platform</title><link>https://jarvis-ai-platform.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Sat, 10 Oct 2026 15:33:07 GMT</lastBuildDate><atom:link href="https://jarvis-ai-platform.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Building a Local-First AI Assistant with Spring Boot 4 and Spring AI 2.0]]></title><description><![CDATA[Your AI. Your Data. Your Machine.

For the last few years, AI development has been dominated by Python.
When developers talk about AI frameworks, the conversation usually revolves around LangChain, Ll]]></description><link>https://jarvis-ai-platform.hashnode.dev/building-a-local-first-ai-assistant-with-spring-boot-4-and-spring-ai-2-0</link><guid isPermaLink="true">https://jarvis-ai-platform.hashnode.dev/building-a-local-first-ai-assistant-with-spring-boot-4-and-spring-ai-2-0</guid><category><![CDATA[AI]]></category><category><![CDATA[Springboot]]></category><category><![CDATA[Open Source]]></category><category><![CDATA[Java]]></category><category><![CDATA[ollama]]></category><category><![CDATA[gemini]]></category><category><![CDATA[personal assistant]]></category><dc:creator><![CDATA[Sujan Lamichhane]]></dc:creator><pubDate>Wed, 03 Jun 2026 13:44:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6a202d2a54e8a60fa0ff6c4d/b2a8fa5a-f63e-46dd-ac96-09db3cb93509.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p><strong>Your AI. Your Data. Your Machine.</strong></p>
</blockquote>
<p>For the last few years, AI development has been dominated by Python.</p>
<p>When developers talk about AI frameworks, the conversation usually revolves around LangChain, LlamaIndex, AutoGPT, CrewAI, and other Python-first ecosystems.</p>
<p>As a Java developer, I kept asking myself:</p>
<p><strong>Where is the equivalent ecosystem for Java?</strong></p>
<p>The answer is that it already exists.</p>
<p>With Spring AI, Spring Boot 4, WebFlux, PostgreSQL, and Ollama, it is now possible to build serious AI applications entirely in Java.</p>
<p>That realization led me to build <strong>Jarvis AI Platform</strong>.</p>
<p>GitHub Repository:</p>
<pre><code class="language-plaintext">https://github.com/sujankim/jarvis-ai-platform
</code></pre>
<h1>The Problem With Most AI Assistants</h1>
<p>Most AI assistants follow the same architecture:</p>
<pre><code class="language-text">Your Message
      ↓
 Cloud Service
      ↓
  AI Model
      ↓
  Response
</code></pre>
<p>Your conversations travel through someone else's infrastructure.</p>
<p>You depend on their uptime.</p>
<p>You depend on their pricing.</p>
<p>You depend on their privacy policies.</p>
<p>If the service changes tomorrow, you're affected immediately.</p>
<p>That model works for many people.</p>
<p>But I wanted something different.</p>
<hr />
<h1>A Local-First Alternative</h1>
<p>Jarvis follows a completely different approach:</p>
<pre><code class="language-text">Your Message
      ↓
 Your Machine
      ↓
    Ollama
      ↓
  AI Model
      ↓
  Response
</code></pre>
<p>Everything stays on your computer.</p>
<p>No data leaves your machine.</p>
<p>No monthly subscription.</p>
<p>No external dependency for core functionality.</p>
<p>That's why the project's philosophy is simple:</p>
<blockquote>
<p><strong>Your AI. Your Data. Your Machine.</strong></p>
</blockquote>
<hr />
<h1>What Is Jarvis AI Platform?</h1>
<p>Jarvis is not just a chatbot.</p>
<p>It is a modular AI orchestration platform designed around the Java ecosystem.</p>
<p>At a high level, the architecture looks like this:</p>
<pre><code class="language-text">Spring Shell CLI / REST API
              │
      Spring Boot 4
              │
      AI Orchestration
              │
    +---------+---------+
    │                   │
OllamaProvider   GeminiProvider
 (Primary)        (Fallback)
    │
 PostgreSQL
(Sessions &amp; Messages)
</code></pre>
<p>The goal is to make AI providers interchangeable while keeping the application architecture clean and maintainable.</p>
<p>Current features in <strong>v0.1.0</strong> include:</p>
<ul>
<li><p>Interactive AI chat with token streaming</p>
</li>
<li><p>JWT authentication</p>
</li>
<li><p>Argon2id password hashing</p>
</li>
<li><p>Session persistence</p>
</li>
<li><p>PostgreSQL storage</p>
</li>
<li><p>Ollama local AI support</p>
</li>
<li><p>Gemini fallback support</p>
</li>
<li><p>Provider abstraction layer</p>
</li>
<li><p>Working memory system</p>
</li>
<li><p>Swagger/OpenAPI integration</p>
</li>
<li><p>Health monitoring and diagnostics</p>
</li>
</ul>
<hr />
<h1>Tech Stack</h1>
<table>
<thead>
<tr>
<th>Layer</th>
<th>Technology</th>
</tr>
</thead>
<tbody><tr>
<td>Language</td>
<td>Java 21</td>
</tr>
<tr>
<td>Framework</td>
<td>Spring Boot 4.0.6</td>
</tr>
<tr>
<td>AI</td>
<td>Spring AI 2.0</td>
</tr>
<tr>
<td>Web</td>
<td>Spring WebFlux</td>
</tr>
<tr>
<td>Security</td>
<td>Spring Security 7</td>
</tr>
<tr>
<td>Authentication</td>
<td>JWT</td>
</tr>
<tr>
<td>Password Hashing</td>
<td>Argon2id</td>
</tr>
<tr>
<td>Database</td>
<td>PostgreSQL 16</td>
</tr>
<tr>
<td>Database Access</td>
<td>R2DBC</td>
</tr>
<tr>
<td>Migrations</td>
<td>Flyway</td>
</tr>
<tr>
<td>CLI</td>
<td>Spring Shell 4</td>
</tr>
<tr>
<td>Local AI</td>
<td>Ollama</td>
</tr>
<tr>
<td>Cloud AI</td>
<td>Gemini</td>
</tr>
<tr>
<td>Mapping</td>
<td>MapStruct 1.6</td>
</tr>
</tbody></table>
<hr />
<h1>Why I Chose Java Instead of Python</h1>
<p>One question I hear often is:</p>
<blockquote>
<p>"Why didn't you build this in Python?"</p>
</blockquote>
<p>The short answer:</p>
<p>Because I enjoy building systems in Java.</p>
<p>The longer answer is that Java provides several advantages for long-term AI applications:</p>
<ul>
<li><p>Strong type safety</p>
</li>
<li><p>Excellent tooling</p>
</li>
<li><p>Mature ecosystem</p>
</li>
<li><p>Production-ready frameworks</p>
</li>
<li><p>Reactive programming support</p>
</li>
<li><p>Enterprise-grade security</p>
</li>
</ul>
<p>Spring AI is making AI development feel like a natural extension of the Spring ecosystem.</p>
<p>Instead of learning an entirely new stack, Java developers can use tools they already know.</p>
<p>That was one of the biggest motivations behind Jarvis.</p>
<hr />
<h1>Architecture Deep Dive</h1>
<p>The most interesting part of Jarvis isn't the CLI.</p>
<p>It isn't PostgreSQL.</p>
<p>It isn't even the AI model.</p>
<p>The most important design decision was the architecture that sits between users and AI providers.</p>
<p>The goal from day one was simple:</p>
<blockquote>
<p>Never lock Jarvis to a single AI provider.</p>
</blockquote>
<p>That requirement shaped the entire system.</p>
<hr />
<h2>1. Provider Abstraction Layer</h2>
<p>Every AI provider in Jarvis implements the same interface.</p>
<pre><code class="language-java">public interface AiProvider {

    Flux&lt;String&gt; streamChat(Prompt prompt);

    Mono&lt;Boolean&gt; isAvailable();

    String getName();

    String getModelName();
}
</code></pre>
<p>Both <code>OllamaProvider</code> and <code>GeminiProvider</code> implement this contract.</p>
<p>That means the rest of the application never needs to know which provider is currently being used.</p>
<p>The provider router handles that responsibility.</p>
<pre><code class="language-java">return ollamaProvider.isAvailable()
    .flatMap(ollamaUp -&gt; {

        if (ollamaUp) {
            return Mono.just((AiProvider) ollamaProvider);
        }

        return geminiProvider.isAvailable()
            .flatMap(geminiUp -&gt; {

                if (geminiUp) {
                    return Mono.just((AiProvider) geminiProvider);
                }

                return Mono.error(
                    new RuntimeException(
                        "No provider available"));
            });
    });
</code></pre>
<p>This creates a provider-agnostic architecture.</p>
<p>If Ollama is running, Jarvis uses Ollama.</p>
<p>If Ollama becomes unavailable, Jarvis automatically falls back to Gemini.</p>
<p>Users don't need to change anything.</p>
<p>The architecture stays the same.</p>
<p>Adding a new provider becomes straightforward:</p>
<pre><code class="language-java">public class ClaudeProvider
        implements AiProvider {
}
</code></pre>
<p>Implement the interface.</p>
<p>Register the provider.</p>
<p>Done.</p>
<p>No orchestrator changes.</p>
<p>No controller changes.</p>
<p>No CLI changes.</p>
<hr />
<h2>2. Reactive Streaming</h2>
<p>One feature I absolutely wanted was real-time token streaming.</p>
<p>I didn't want users waiting ten seconds for an entire response.</p>
<p>I wanted responses to appear immediately.</p>
<p>That requirement pushed the project toward a fully reactive architecture.</p>
<p>The flow looks like this:</p>
<pre><code class="language-text">Ollama
   ↓
Spring AI
   ↓
Flux&lt;String&gt;
   ↓
AiOrchestrator
   ↓
SSE Endpoint
   ↓
CLI Client
   ↓
Terminal Output
</code></pre>
<p>Each token moves through the pipeline independently.</p>
<p>The user starts seeing output almost immediately.</p>
<p>The controller endpoint looks like this:</p>
<pre><code class="language-java">@PostMapping(
    value = "/stream",
    produces = MediaType.TEXT_EVENT_STREAM_VALUE
)
public Flux&lt;ServerSentEvent&lt;String&gt;&gt; stream(
        @Valid @RequestBody ChatRequest request) {

    return orchestrator.chat(...)
            .map(token -&gt;
                    ServerSentEvent
                            .&lt;String&gt;builder()
                            .event("token")
                            .data(token)
                            .build());
}
</code></pre>
<p>The result feels significantly faster than waiting for a complete response.</p>
<p>Even when generation takes several seconds, users immediately know something is happening.</p>
<p>That small improvement dramatically improves user experience.</p>
<hr />
<h2>3. The Whitespace Bug</h2>
<p>One of the strangest bugs I encountered involved spaces.</p>
<p>Responses looked like this:</p>
<pre><code class="language-text">Hellohowareyoutoday?
</code></pre>
<p>Instead of:</p>
<pre><code class="language-text">Hello how are you today?
</code></pre>
<p>The cause turned out to be Server Sent Events.</p>
<p>Leading whitespace inside tokens was being lost during transmission.</p>
<p>The fix was surprisingly simple.</p>
<p>Instead of sending raw text, I wrapped every token in JSON.</p>
<pre><code class="language-java">private String jsonToken(String token) {

    return "{\"t\":\""
            + token
                .replace("\\", "\\\\")
                .replace("\"", "\\\"")
                .replace("\n", "\\n")
            + "\"}";
}
</code></pre>
<p>The client then extracts the value from the JSON payload.</p>
<p>Problem solved.</p>
<p>Sometimes the hardest bugs are not AI-related at all.</p>
<p>They're just spaces.</p>
<hr />
<h2>4. Working Memory</h2>
<p>One of the most common questions I receive is:</p>
<blockquote>
<p>How does Jarvis know today's date?</p>
</blockquote>
<p>The answer is simple.</p>
<p>We provide that information.</p>
<p>Before every request, Jarvis generates a small working-memory block.</p>
<pre><code class="language-java">@Component
public class WorkingMemoryBuilder {

    public String build(
            String username,
            String role,
            String sessionId,
            String modelName) {

        String currentTime =
                ZonedDateTime.now()
                        .format(...);

        return """
                Date: %s
                User: %s
                Role: %s
                Session: %s
                Model: %s
                """
                .formatted(
                        currentTime,
                        username,
                        role,
                        sessionId,
                        modelName);
    }
}
</code></pre>
<p>This memory is injected into every prompt.</p>
<p>The AI isn't magically aware of the current date.</p>
<p>The application simply tells it.</p>
<p>Understanding that distinction helped me better understand how modern LLM applications actually work.</p>
<p>Much of what appears intelligent is often carefully engineered context.</p>
<hr />
<h2>5. Prompt Assembly</h2>
<p>Every user request passes through a component called <code>PromptAssembler</code>.</p>
<p>Its job is to construct the final prompt.</p>
<p>The assembled prompt contains four pieces:</p>
<ol>
<li><p>System instructions</p>
</li>
<li><p>Working memory</p>
</li>
<li><p>Session history</p>
</li>
<li><p>Current user message</p>
</li>
</ol>
<p>Simplified version:</p>
<pre><code class="language-java">messages.add(systemPrompt);

messages.add(workingMemory);

messages.addAll(history);

messages.add(
    new UserMessage(userMessage));

return new Prompt(messages);
</code></pre>
<p>This process gives the AI everything it needs to generate contextual responses.</p>
<p>Without prompt assembly, the AI would only see the current message.</p>
<p>With prompt assembly, it understands:</p>
<ul>
<li><p>who the user is</p>
</li>
<li><p>previous conversation history</p>
</li>
<li><p>current date and time</p>
</li>
<li><p>session context</p>
</li>
<li><p>assistant instructions</p>
</li>
</ul>
<p>This is where much of the "assistant" behavior actually comes from.</p>
<hr />
<h2>6. Spring Shell 4.0</h2>
<p>Jarvis uses Spring Shell as its primary interface.</p>
<p>One challenge was adapting to the changes introduced in Spring Shell 4.</p>
<p>Previous versions used annotations such as:</p>
<pre><code class="language-java">@ShellComponent
@ShellMethod
</code></pre>
<p>Those annotations were removed.</p>
<p>The new approach uses:</p>
<pre><code class="language-java">@Component
public class AuthCommands {

    @Command(
        name = "login",
        description = "Login to Jarvis")
    public String login() {
        return "OK";
    }
}
</code></pre>
<p>The migration wasn't difficult.</p>
<p>The real challenge came from JLine integration.</p>
<p>I encountered a circular dependency involving <code>LineReader</code>.</p>
<p>The solution was lazy injection.</p>
<pre><code class="language-java">public AuthCommands(
        CliStateManager state,
        CliHttpClient http,
        @Lazy LineReader lineReader) {

    this.state = state;
    this.http = http;
    this.lineReader = lineReader;
}
</code></pre>
<p>That single annotation solved hours of debugging.</p>
<hr />
<h2>7. Reactive Security</h2>
<p>Spring Security behaves differently in reactive applications.</p>
<p>Traditional applications rely heavily on <code>ThreadLocal</code>.</p>
<p>Reactive applications cannot.</p>
<p>Requests may move across multiple threads.</p>
<p>Instead, WebFlux uses Reactor Context.</p>
<pre><code class="language-java">return chain.filter(exchange)
    .contextWrite(
        ReactiveSecurityContextHolder
            .withAuthentication(auth));
</code></pre>
<p>Authentication information travels with the reactive stream itself.</p>
<p>Once I understood that concept, many WebFlux security patterns suddenly made much more sense.</p>
<hr />
<h1>Quick Start</h1>
<p>Getting Jarvis running locally takes only a few minutes.</p>
<h3>Prerequisites</h3>
<ul>
<li><p>Java 21+</p>
</li>
<li><p>Docker</p>
</li>
<li><p>Ollama</p>
</li>
</ul>
<h3>1. Clone the Repository</h3>
<pre><code class="language-bash">git clone https://github.com/sujankim/jarvis-ai-platform.git

cd jarvis-ai-platform
</code></pre>
<h3>2. Download a Local Model</h3>
<pre><code class="language-bash">ollama pull llama3.1:8b
</code></pre>
<p>This is a one-time download of approximately 5 GB.</p>
<h3>3. Configure Environment Variables</h3>
<pre><code class="language-bash">cp .env.example .env
</code></pre>
<p>Update the <code>.env</code> file and set a secure JWT secret.</p>
<pre><code class="language-text">JARVIS_JWT_SECRET=your-secret-key
</code></pre>
<h3>4. Start PostgreSQL</h3>
<pre><code class="language-bash">docker-compose up -d
</code></pre>
<h3>5. Run Jarvis</h3>
<pre><code class="language-bash">cd server

./mvnw spring-boot:run
</code></pre>
<h3>Example Session</h3>
<pre><code class="language-text">jarvis:&gt; login

Username: dravin
Password: ******

Welcome back, Dravin!

jarvis:&gt; chat

You: Hello Jarvis! What day is it today?

Jarvis: Today is Tuesday, June 3, 2026.

You: exit
</code></pre>
<p>At this point, everything is running locally on your machine.</p>
<p>No cloud dependency is required.</p>
<hr />
<h1>What I Learned</h1>
<p>Building Jarvis taught me far more than I expected.</p>
<p>Some lessons came from AI.</p>
<p>Most came from software engineering.</p>
<hr />
<h2>Reactive Programming Is Harder Than Traditional MVC</h2>
<p>There is no point pretending otherwise.</p>
<p>A traditional Spring MVC application is easier to build.</p>
<p>A traditional JPA repository is easier to understand.</p>
<p>A blocking HTTP client is easier to debug.</p>
<p>But AI applications are fundamentally streaming applications.</p>
<p>Responses often take several seconds to generate.</p>
<p>Blocking threads while waiting for tokens simply doesn't make sense.</p>
<p>The reactive stack allowed me to:</p>
<ul>
<li><p>Stream responses in real time</p>
</li>
<li><p>Handle multiple conversations efficiently</p>
</li>
<li><p>Avoid thread starvation</p>
</li>
<li><p>Build a true end-to-end streaming pipeline</p>
</li>
</ul>
<p>The learning curve was steep.</p>
<p>However, AI workloads are fundamentally different from typical CRUD applications.</p>
<p>When a language model spends 10–30 seconds generating a response, blocking threads becomes expensive.</p>
<p>Reactive streaming solves that problem elegantly.</p>
<p>Instead of waiting for the entire response to finish, tokens flow through the system as they are generated.</p>
<pre><code class="language-text">Ollama
   ↓
Spring AI
   ↓
Flux&lt;String&gt;
   ↓
Server-Sent Events
   ↓
CLI Client
   ↓
Terminal Output
</code></pre>
<p>The result is a much more responsive experience.</p>
<p>Users begin receiving output immediately instead of waiting for a complete response.</p>
<p>For AI applications, that difference feels enormous.</p>
<p>The payoff was worth it.</p>
<hr />
<h2>Spring AI Feels Like Spring</h2>
<p>One thing I appreciate about Spring AI is that it doesn't feel like a separate ecosystem.</p>
<p>It feels like Spring.</p>
<p>Builders.</p>
<p>Dependency injection.</p>
<p>Configuration properties.</p>
<p>Auto-configuration.</p>
<p>The same conventions Java developers already know.</p>
<p>Creating an Ollama client feels familiar.</p>
<p>Creating a Gemini client feels familiar.</p>
<p>Switching between providers feels familiar.</p>
<p>That consistency significantly reduces friction.</p>
<hr />
<h2>Local AI Is Better Than Most People Think</h2>
<p>Before building Jarvis, I assumed local models would be too slow or too limited.</p>
<p>I was wrong.</p>
<p>Running <code>llama3.1:8b</code> locally produces surprisingly useful results.</p>
<p>For:</p>
<ul>
<li><p>General questions</p>
</li>
<li><p>Brainstorming</p>
</li>
<li><p>Coding assistance</p>
</li>
<li><p>Documentation help</p>
</li>
<li><p>Learning</p>
</li>
</ul>
<p>it performs remarkably well.</p>
<p>Is it as capable as the largest cloud models?</p>
<p>No.</p>
<p>Does it need to be?</p>
<p>Also no.</p>
<p>For many personal workflows, local models are already good enough.</p>
<p>And the privacy benefits are enormous.</p>
<hr />
<h2>Architecture Matters More Than Models</h2>
<p>This was probably the biggest lesson.</p>
<p>People often focus entirely on the model.</p>
<p>GPT.</p>
<p>Claude.</p>
<p>Gemini.</p>
<p>Llama.</p>
<p>Mistral.</p>
<p>But real AI applications are mostly architecture.</p>
<p>Prompt management.</p>
<p>Memory.</p>
<p>Security.</p>
<p>Persistence.</p>
<p>Streaming.</p>
<p>Observability.</p>
<p>Provider routing.</p>
<p>Error handling.</p>
<p>The model is only one piece of the system.</p>
<p>Building Jarvis reinforced that idea repeatedly.</p>
<hr />
<h1>What's Next?</h1>
<p>Jarvis is still early.</p>
<p>Version 0.1.0 focuses on the foundation.</p>
<p>Future releases will add significantly more capabilities.</p>
<hr />
<h2>Phase 2 — Memory System</h2>
<p>Current conversations are session-based.</p>
<p>Future versions will introduce persistent memory.</p>
<p>Planned features include:</p>
<ul>
<li><p>Long-term memory</p>
</li>
<li><p>User preferences</p>
</li>
<li><p>Redis caching</p>
</li>
<li><p>Semantic retrieval</p>
</li>
<li><p>pgvector integration</p>
</li>
</ul>
<p>The goal is simple:</p>
<p>Jarvis should remember useful information across sessions.</p>
<hr />
<h2>Phase 3 — RAG Engine</h2>
<p>Retrieval-Augmented Generation is one of the most requested features.</p>
<p>Planned capabilities:</p>
<ul>
<li><p>PDF ingestion</p>
</li>
<li><p>Knowledge bases</p>
</li>
<li><p>Semantic search</p>
</li>
<li><p>Document chat</p>
</li>
<li><p>Context-aware answers</p>
</li>
</ul>
<p>Instead of asking only the model, users will be able to ask their own documents.</p>
<hr />
<h2>Phase 4 — Tool Engine</h2>
<p>The next major step is action-taking.</p>
<p>Examples:</p>
<ul>
<li><p>Weather tools</p>
</li>
<li><p>Search tools</p>
</li>
<li><p>Calculators</p>
</li>
<li><p>External integrations</p>
</li>
<li><p>MCP support</p>
</li>
</ul>
<p>At that point Jarvis becomes more than a conversational assistant.</p>
<p>It becomes an assistant that can actually do things.</p>
<hr />
<h2>Phase 5 — Voice</h2>
<p>Eventually Jarvis will gain voice capabilities.</p>
<p>The long-term vision is a genuinely useful local AI assistant that remains private and self-hosted.</p>
<hr />
<hr />
<h2>Phase 6 — Agent System</h2>
<p>Longer-term plans include:</p>
<ul>
<li><p>Agent planning</p>
</li>
<li><p>Multi-step execution</p>
</li>
<li><p>Workflow automation</p>
</li>
<li><p>Tool orchestration</p>
</li>
</ul>
<p>The ultimate goal is to move beyond chat and build a true personal AI assistant.</p>
<hr />
<h2>Phase 7 - Web UI</h2>
<p>Beautiful web interface powered by the same backend.</p>
<p>Features:</p>
<ul>
<li><p>Real-time streaming chat</p>
</li>
<li><p>Session sidebar</p>
</li>
<li><p>Document upload UI</p>
</li>
<li><p>Memory management</p>
</li>
<li><p>Settings panel</p>
</li>
<li><p>Agent dashboard</p>
</li>
<li><p>Voice interface</p>
</li>
</ul>
<hr />
<h1>Contributing</h1>
<p>Jarvis is open source and actively looking for contributors.</p>
<p>Whether you're experienced with Java or just learning Spring Boot, contributions are welcome.</p>
<p>Some beginner-friendly areas include:</p>
<ul>
<li><p>Documentation improvements</p>
</li>
<li><p>Unit tests</p>
</li>
<li><p>CLI enhancements</p>
</li>
<li><p>New provider integrations</p>
</li>
<li><p>Bug fixes</p>
</li>
<li><p>Architecture diagrams</p>
</li>
</ul>
<p>Repository:</p>
<pre><code class="language-text">https://github.com/sujankim/jarvis-ai-platform
</code></pre>
<p>If you'd like to contribute, start with:</p>
<pre><code class="language-text">CONTRIBUTING.md
</code></pre>
<p>and look for issues labeled:</p>
<pre><code class="language-text">good first issue
</code></pre>
<hr />
<h1>Conclusion</h1>
<p>When I started this project, I wasn't trying to build the next ChatGPT.</p>
<p>I was trying to answer a simple question:</p>
<blockquote>
<p>Can modern AI applications be built effectively in Java?</p>
</blockquote>
<p>After building Jarvis, my answer is absolutely yes.</p>
<p>The Java ecosystem has matured rapidly.</p>
<p>Spring Boot 4 provides an excellent foundation.</p>
<p>Spring AI removes much of the complexity involved in provider integrations.</p>
<p>WebFlux enables real-time streaming.</p>
<p>Ollama makes local AI practical.</p>
<p>Most importantly, the ecosystem finally feels ready.</p>
<p>If you're a Java developer who has been watching the AI space from the sidelines, there has never been a better time to start building.</p>
<p>The tools exist.</p>
<p>The frameworks exist.</p>
<p>The community is growing.</p>
<p>Now it's time to build.</p>
<p>If you found this article useful, I'd love to hear your thoughts.</p>
<p>Questions, suggestions, architecture feedback, and contributions are always welcome.</p>
<p>⭐ If you'd like to support the project, consider starring the repository:</p>
<pre><code class="language-text">https://github.com/sujankim/jarvis-ai-platform
</code></pre>
<p><strong>Your AI. Your Data. Your Machine.</strong></p>
]]></content:encoded></item></channel></rss>