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.
<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.
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.
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; }
}
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
<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.
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.
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
<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.
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.
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.
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:
<dependency>
<groupId>uno.anahata</groupId>
<artifactId>anahata-asi-nb</artifactId>
<version>1.0.0</version>
<type>nbm</type>
</dependency>
Module Installer
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.
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 theRebindableinterface. 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. recreatingPropertyChangeSupport). Always invokesuper.rebind()first!postActivate()(Late Stage): Triggered by the framework later, after the entire session object graph is fully reconstructed and bound to the hostAsiContainer. This is the safe, authoritative place to run logic that depends on other toolkits, active connections, your parentAgisession, or the host container.
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;
}
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.
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);
}
}