Developer Quick Start

From zero to Artificial Super Intelligence in 5 minutes.

This guide will walk you through setting up an ASI Container, registering an AI provider, creating a custom tool, and running your very first agentic loop.

Requirements

Java 21 or higher, Maven, and an API key for a supported provider (e.g., Google Gemini, OpenAI, Anthropic, or a local Ollama instance).

Deployment Models

Anahata ASI is designed to run in multiple environments. Choose the model that fits your application:

For background services, CLI tools, or custom backend orchestrators.

1. Dependencies

For a headless environment, you only need the core framework and an AI provider adapter.

pom.xml
<dependencies>
    <dependency>
        <groupId>uno.anahata</groupId>
        <artifactId>anahata-asi-core</artifactId>
        <version>1.0.0</version>
    </dependency>
    <dependency>
        <groupId>uno.anahata</groupId>
        <artifactId>anahata-asi-gemini</artifactId>
        <version>1.0.0</version>
    </dependency>
</dependencies>

2. Configuration (DNA)

The AgiConfig defines the default AI provider, model, and which toolkits are enabled for the session.

MyAppAgiConfig.java
import uno.anahata.asi.agi.AgiConfig;
import uno.anahata.asi.AbstractAsiContainer;

public class MyAppAgiConfig extends AgiConfig {
    public MyAppAgiConfig(AbstractAsiContainer container) {
        super(container);
        setSelectedProviderUuid("Gemini");
        setSelectedModelId("models/gemini-3.5-flash");
        
        // Register your custom toolkit!
        getToolClasses().add(EnterpriseToolkit.class);
    }
}

3. Container & Main

The AbstractAsiContainer acts as the host application, managing session lifecycles.

MyAppAsiContainer.java
import uno.anahata.asi.AbstractAsiContainer;
import uno.anahata.asi.agi.Agi;
import uno.anahata.asi.agi.AgiConfig;

public class MyAppAsiContainer extends AbstractAsiContainer {
    public MyAppAsiContainer() {
        super("my-headless-app");
    }

    @Override
    public AgiConfig createNewAgiConfig() {
        return new MyAppAgiConfig(this);
    }

    @Override protected void onAgiOpened(Agi agi) {}
    @Override protected void onAgiClosed(Agi agi) {}
    @Override public Object getUI(Agi agi) { return null; }
}
Main.java
import uno.anahata.asi.agi.Agi;
import uno.anahata.asi.gemini.GeminiAiProvider;
import uno.anahata.asi.agi.message.InputUserMessage;

public class Main {
    public static void main(String[] args) {
        MyAppAsiContainer container = new MyAppAsiContainer();
        container.registerProvider(new GeminiAiProvider());
        // API key is loaded from ~/.anahata/asi/my-headless-app/Gemini/api_keys.txt
        
        Agi agi = container.createNewAgi();
        
        // Inject the custom context provider
        agi.getContextManager().registerContextProvider(new DatabaseContextProvider());
        
        InputUserMessage msg = new InputUserMessage(agi);
        msg.setText("What is the current database status? Also, calculate the projected revenue for EMEA.");
        agi.sendMessage(msg);
    }
}

Embed the ASI Chat UI and Tool Viewers into an existing Swing Application.

Dependencies

pom.xml
    <dependency>
        <groupId>uno.anahata</groupId>
        <artifactId>anahata-asi-swing</artifactId>
        <version>1.0.0</version>
    </dependency>

Embedded Configuration & Toolkits

Define your session DNA and register any custom toolkits you want to expose to the AI.

EmbeddedSwingAppAgiConfig.java
import uno.anahata.asi.swing.agi.SwingAgiConfig;
import uno.anahata.asi.AbstractAsiContainer;

public class EmbeddedSwingAppAgiConfig extends SwingAgiConfig {
    public EmbeddedSwingAppAgiConfig(AbstractAsiContainer container) {
        super(container);
        // Register a custom toolkit specific to your embedded app
        getToolClasses().add(MyCustomBusinessToolkit.class);
    }
}

Container & Dashboard (Cards View)

While AsiDesktopAsiContainer auto-manages tabs, embedding via AbstractSwingAsiContainer directly gives you absolute control over where the AI chat appears (e.g., floating windows, internal frames, or custom tab managers). You provide this integration logic via getUI, focusUI, and closeUI.

To display the session dashboard (like the sticky-note cards), simply instantiate an AsiCardsContainerPanel.

EmbeddedSwingAppAsiContainer.java
import uno.anahata.asi.swing.AbstractSwingAsiContainer;
import uno.anahata.asi.swing.AsiCardsContainerPanel;
import uno.anahata.asi.swing.agi.AgiPanel;
import uno.anahata.asi.agi.Agi;
import uno.anahata.asi.agi.AgiConfig;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.swing.JTabbedPane;

public class EmbeddedSwingAppAsiContainer extends AbstractSwingAsiContainer {
    private final JTabbedPane appTabs; // Your app's existing tab manager
    // Cache to ensure we only create one UI panel per session!
    private final Map<String, AgiPanel> activePanels = new ConcurrentHashMap<>();

    public EmbeddedSwingAppAsiContainer(JTabbedPane appTabs) {
        super("my-embedded-app");
        this.appTabs = appTabs;
        
        // Render the out-of-the-box Cards Dashboard
        AsiCardsContainerPanel dashboard = new AsiCardsContainerPanel(this);
        appTabs.addTab("AI Sessions", dashboard);
    }

    @Override
    public AgiConfig createNewAgiConfig() {
        return new EmbeddedSwingAppAgiConfig(this);
    }

    // --- The orchestration contract ---
    // You define exactly how your app displays an individual AI session!

    @Override
    public AgiPanel getUI(Agi agi) {
        // CRITICAL: Always cache and return the same panel instance for a given session
        return activePanels.computeIfAbsent(agi.getConfig().getSessionId(), id -> {
            AgiPanel panel = new AgiPanel(agi);
            panel.initComponents();
            
            // Customization: Remove the Support and CwGC tabs for a cleaner embedded look
            panel.getTabbedPane().remove(panel.getSupportPanel());
            panel.getTabbedPane().remove(panel.getCwGcPanel());
            
            return panel;
        });
    }
    
    @Override 
    protected void focusUI(Agi agi) {
        // E.g., open a new tab in your app for this specific session
        AgiPanel panel = getAgiPanel(agi);
        if (appTabs.indexOfComponent(panel) == -1) {
            appTabs.addTab(agi.getNickname(), panel);
        }
        appTabs.setSelectedComponent(panel);
    }
    
    @Override 
    protected void closeUI(Agi agi) { 
        AgiPanel panel = activePanels.remove(agi.getConfig().getSessionId());
        if (panel != null) {
            appTabs.remove(panel);
        }
    }
}

Build a customized standalone AI Desktop app using the ASI Desktop framework.

1. Dependencies

pom.xml
    <dependency>
        <groupId>uno.anahata</groupId>
        <artifactId>anahata-asi-desktop</artifactId>
        <version>1.0.0</version>
    </dependency>

2. Container & Config

Extend AsiDesktopAsiContainer and define your custom default providers and configuration.

MyAsiContainer.java
import uno.anahata.asi.destkop.swing.AsiDesktopAsiContainer;
import uno.anahata.asi.agi.AgiConfig;

public class MyAsiContainer extends AsiDesktopAsiContainer {
    public MyAsiContainer() {
        super("MyCustomApp");
        // Register custom providers here if needed
    }

    @Override
    public AgiConfig createNewAgiConfig() {
        return new MyAgiConfig(this);
    }
}

3. Main Panel (Dashboard)

Extend AsiDesktopMainPanel to inject your own application-specific tabs alongside the AI container.

MyMainPanel.java
import uno.anahata.asi.destkop.swing.AsiDesktopMainPanel;

public class MyMainPanel extends AsiDesktopMainPanel {
    public MyMainPanel(MyAsiContainer container) {
        super(container);
        // Add custom application tabs next to the ASI dashboard
        tabbedPane.addTab("📈 Custom Dashboard", new MyCustomPanel());
        
        // Prevent closing the custom dashboard
        tabbedPane.putClientProperty("JTabbedPane.tabCloseCondition", 
            (java.util.function.Predicate<Integer>) tabIndex -> tabIndex > 0);
    }
}

4. Application Launcher

Bootstrap the FlatLaf theme and display your custom JFrame.

Main.java
import com.formdev.flatlaf.FlatLightLaf;
import javax.swing.*;
import java.awt.BorderLayout;

public class Main {
    public static void main(String[] args) {
        try { UIManager.setLookAndFeel(new FlatLightLaf()); } catch (Exception e) {}
        
        MyAsiContainer container = new MyAsiContainer();
        
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("My ASI Desktop App");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            
            MyMainPanel mainPanel = new MyMainPanel(container);
            frame.add(mainPanel, BorderLayout.CENTER);
            
            frame.setSize(1400, 900);
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
            
            mainPanel.start();
        });
    }
}

Create a NetBeans module that extends Anahata ASI Studio with custom toolkits.

Dependencies

Declare the Anahata Studio API dependency in your suite or standalone NBM module POM:

pom.xml
<dependency>
    <groupId>uno.anahata</groupId>
    <artifactId>anahata-asi-nb</artifactId>
    <version>1.0.0</version>
    <type>nbm</type>
</dependency>

Module Installer

MyModuleInstaller.java
import org.openide.modules.ModuleInstall;
import uno.anahata.asi.nb.AnahataInstaller;

public class MyModuleInstaller extends ModuleInstall {
    @Override
    public void restored() {
        // Register your custom toolkit into the global ASI environment templates
        AnahataInstaller.getContainer().getPreferences()
            .getAgiTemplate().getToolClasses().add(MyCustomToolkit.class);
    }
}

Creating Custom Tools (Toolkits)

Toolkits grant the ASI the ability to take action. By extending AnahataToolkit and annotating methods with @AgiTool, the SchemaProvider generates OpenAPI schemas automatically, allowing any model to invoke your custom code securely.

EnterpriseToolkit.java
import uno.anahata.asi.agi.tool.AnahataToolkit;
import uno.anahata.asi.agi.tool.AgiToolkit;
import uno.anahata.asi.agi.tool.AgiTool;
import uno.anahata.asi.agi.tool.AgiToolParam;

@AgiToolkit("Enterprise operations and revenue management.")
public class EnterpriseToolkit extends AnahataToolkit {
    @AgiTool("Calculates the total revenue for a given region.")
    public double calculateRevenue(
            @AgiToolParam("The target region (e.g., 'EMEA', 'NA').") String region,
            @AgiToolParam("Whether to include projected sales.") boolean includeProjected) {
        
        log("Calculating revenue for region: " + region); // Thread-safe logging!
        return includeProjected ? 1500000.0 : 1000000.0;
    }
}

Advanced Toolkits & Lifecycle Management

For complex enterprise integrations, toolkits must manage their own state persistence (Kryo serialization), interact with external resources, and integrate tightly with the ASI's prompt-assembly phase. To do this, your toolkit can leverage POJOs, transient fields, prompt-population callbacks, and early/late deserialization recovery hooks.

Rebind vs. PostActivate Lifecycle Hooks

Because Anahata passivates and serializes the entire Agi session graph to a .kryo binary file on every turn, fields marked as transient (like database connections, threads, or UI listener supports) will be skipped during serialization. You must recover them on deserialization using our two-stage lifecycle hooks:

  • rebind() (Early Stage): Part of the Rebindable interface. Triggered immediately as soon as Kryo finishes deserializing your specific toolkit object, before the rest of the session graph is built. It is reserved strictly for restoring local transient variables (e.g. recreating PropertyChangeSupport). Always invoke super.rebind() first!
  • postActivate() (Late Stage): Triggered by the framework later, after the entire session object graph is fully reconstructed and bound to the host AsiContainer. This is the safe, authoritative place to run logic that depends on other toolkits, active connections, your parent Agi session, or the host container.
ProjectMetadata.java (POJO Parameter Model)
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.Getter;

@Getter
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "Structured metadata describing an enterprise engineering project.")
public class ProjectMetadata {
    @Schema(description = "The unique identifier of the project.", required = true)
    private String projectId;

    @Schema(description = "The target deployment region.", example = "EMEA")
    private String region;

    @Schema(description = "The current development budget.")
    private double budget;
}
AdvancedEnterpriseToolkit.java
import java.beans.PropertyChangeSupport;
import java.util.List;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Files;
import lombok.extern.slf4j.Slf4j;
import uno.anahata.asi.agi.tool.AnahataToolkit;
import uno.anahata.asi.agi.tool.AgiToolkit;
import uno.anahata.asi.agi.tool.AgiTool;
import uno.anahata.asi.agi.tool.AgiToolParam;
import uno.anahata.asi.agi.message.RagMessage;

@Slf4j
@AgiToolkit("High-performance enterprise toolkit with state persistence and JIT prompt integration.")
public class AdvancedEnterpriseToolkit extends AnahataToolkit {

    // Persistent field: Automatically saved to Kryo on every turn
    private String currentAuditId = "INIT-AUDIT";

    // Transient fields: Skipped by Kryo, must be recovered manually
    private transient PropertyChangeSupport propertyChangeSupport;
    private transient MyDatabaseConnection dbConnection;

    // --- 1. Deserialization & Lifecycle Recovery ---

    @Override
    public void rebind() {
        super.rebind(); // CRITICAL: Always invoke parent rebind first!
        log.debug("Early stage: Recreating transient PropertyChangeSupport");
        this.propertyChangeSupport = new PropertyChangeSupport(this);
    }

    @Override
    public void postActivate() {
        super.postActivate(); // Always invoke parent postActivate
        log.debug("Late stage: Re-establishing transient database connection");
        this.dbConnection = new MyDatabaseConnection(getAsiContainer().getHostId());
    }

    // --- 2. Prompt-Augmentation Integration ---

    @Override
    public List getSystemInstructions() throws Exception {
        // Automatically appends custom instructions to the AI's global system prompt on every turn
        return List.of("Strictly audit all transaction budgets under AdvancedEnterpriseToolkit before approving.");
    }

    @Override
    public void populateMessage(RagMessage ragMessage) throws Exception {
        // Injects dynamic, real-time RAG context at the beginning of each turn
        String dbStatus = (dbConnection != null && dbConnection.isAlive()) ? "CONNECTED" : "DISCONNECTED";
        ragMessage.addTextPart("## Advanced Enterprise Context\n"
                + "- Current Audit: " + currentAuditId + "\n"
                + "- DB Connection Status: " + dbStatus);
    }

    // --- 3. AI-Callable Tool Method ---

    @AgiTool("Audits project metadata, writes reports, and attaches the binary receipts.")
    public String auditProject(
            @AgiToolParam("The structured metadata of the target project.") ProjectMetadata metadata
    ) {
        // Operation check: Streaming log/error back to the AI panel
        if (metadata.getBudget() <= 0) {
            error("Validation failed: Budget must be a positive number."); // AI sees this in 'Errors'
            return "Audit failed due to invalid budget constraints.";
        }

        this.currentAuditId = "AUDIT-" + metadata.getProjectId();
        log("Executing audit on: " + currentAuditId); // AI sees this in 'Logs'

        try {
            // Write report to disk
            Path reportPath = Path.of("/tmp/" + currentAuditId + "-report.txt");
            Files.writeString(reportPath, "Pristine Audit completed for " + metadata.getProjectId());
            
            // Programmatically attach the report binary directly to the AI's tool response!
            addAttachment(reportPath); 
            
            return "Audit successfully completed. Report attached as a response binary.";
        } catch (IOException e) {
            log.error("Internal filesystem error", e); // Writes to system slf4j logs
            error("Failed to write report file: " + e.getMessage()); // Writes to AI's error log
            return "Audit completed, but failed to attach binary receipt.";
        }
    }
}

Custom Context Providers

Context providers act as "sensors", injecting real-time data, files, active database states, or runtime telemetry into the ASI's prompt at the beginning of each turn.

DatabaseContextProvider.java
import uno.anahata.asi.agi.context.BasicContextProvider;
import uno.anahata.asi.agi.message.RagMessage;

public class DatabaseContextProvider extends BasicContextProvider {
    public DatabaseContextProvider() {
        super("db-sensor", "Database Status", "Monitors active DB connections.");
    }

    @Override
    public void populateMessage(RagMessage ragMessage) throws Exception {
        int activeConnections = 42; // Example logic
        ragMessage.addTextPart("## Database Status\n- Active Connections: " + activeConnections);
    }
}