ironclaw 0.5.0

Secure personal AI assistant that protects your data and expands its capabilities on the fly
Documentation
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>IronClaw</title>
  <link rel="stylesheet" href="/style.css">
  <script
    src="https://cdn.jsdelivr.net/npm/marked@17.0.2/lib/marked.umd.min.js"
    integrity="sha384-pN9zSKOnTZwXRtYZAu0PBPEgR2B7DOC1aeLxQ33oJ0oy5iN1we6gm57xldM2irDG"
    crossorigin="anonymous"
  ></script>
</head>
<body>
  <!-- Auth Screen -->
  <div id="auth-screen">
    <div class="auth-card-login">
      <div class="auth-brand">
        <h1>IronClaw</h1>
        <p class="auth-tagline">Secure AI Assistant</p>
      </div>
      <div class="auth-form">
        <label for="token-input">Gateway Token</label>
        <input type="password" id="token-input" placeholder="Paste your auth token" autofocus>
        <button onclick="authenticate()">Connect</button>
      </div>
      <div id="auth-error"></div>
      <p class="auth-hint">Enter the GATEWAY_AUTH_TOKEN from your .env configuration.</p>
    </div>
  </div>

  <!-- Main App (hidden until authenticated) -->
  <div id="app">
    <!-- Tab Bar -->
    <div class="tab-bar">
      <button class="active" data-tab="chat">Chat</button>
      <button data-tab="memory">Memory</button>
      <button data-tab="jobs">Jobs</button>
      <button data-tab="logs">Logs</button>
      <button data-tab="routines">Routines</button>
      <button data-tab="extensions">Extensions</button>
      <div class="spacer"></div>
      <div class="status" id="gateway-status-trigger">
        <div class="dot" id="sse-dot"></div>
        <span id="sse-status">Connected</span>
        <div class="gateway-popover" id="gateway-popover"></div>
      </div>
    </div>

    <!-- Chat Tab -->
    <div class="tab-panel active" id="tab-chat">
      <div class="thread-sidebar" id="thread-sidebar">
        <div class="thread-sidebar-header">
          <span>Threads</span>
          <button class="thread-new-btn" onclick="createNewThread()" title="New thread (Ctrl/Cmd+N)">+</button>
          <button class="thread-toggle-btn" id="thread-toggle-btn" onclick="toggleThreadSidebar()" title="Toggle sidebar">&laquo;</button>
        </div>
        <div class="assistant-item" id="assistant-thread" onclick="switchToAssistant()">
          <span class="assistant-label">Assistant</span>
          <span class="assistant-meta" id="assistant-meta"></span>
        </div>
        <div class="threads-section-header">
          <span>Conversations</span>
        </div>
        <div class="thread-list" id="thread-list"></div>
      </div>
      <div class="chat-container">
        <div class="chat-messages" id="chat-messages"></div>
        <div class="chat-status" id="chat-status"></div>
        <div class="chat-input">
          <textarea id="chat-input" placeholder="Type a message..." rows="1"></textarea>
          <button id="send-btn" onclick="sendMessage()">Send</button>
        </div>
      </div>
    </div>

    <!-- Memory Tab -->
    <div class="tab-panel" id="tab-memory">
      <div class="memory-container">
        <div class="memory-sidebar">
          <div class="search-box">
            <input type="text" id="memory-search" placeholder="Search memory...">
          </div>
          <div class="memory-tree" id="memory-tree"></div>
        </div>
        <div class="memory-content">
          <div class="memory-breadcrumb" id="memory-breadcrumb">
            <span id="memory-breadcrumb-path">workspace /</span>
            <button class="memory-edit-btn" id="memory-edit-btn" style="display:none" onclick="startMemoryEdit()">Edit</button>
          </div>
          <div class="memory-viewer" id="memory-viewer">
            <div class="empty">Select a file to view its contents</div>
          </div>
          <div class="memory-editor" id="memory-editor" style="display:none">
            <textarea id="memory-edit-textarea"></textarea>
            <div class="memory-editor-actions">
              <button class="btn-save" onclick="saveMemoryEdit()">Save</button>
              <button class="btn-cancel-edit" onclick="cancelMemoryEdit()">Cancel</button>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- Jobs Tab -->
    <div class="tab-panel" id="tab-jobs">
      <div class="jobs-container">
        <div class="jobs-summary" id="jobs-summary"></div>
        <table class="jobs-table" id="jobs-table">
          <thead>
            <tr>
              <th>ID</th>
              <th>Title</th>
              <th>Source</th>
              <th>Status</th>
              <th>Created</th>
              <th>Actions</th>
            </tr>
          </thead>
          <tbody id="jobs-tbody"></tbody>
        </table>
        <div class="empty-state" id="jobs-empty" style="display:none">No jobs found</div>
      </div>
    </div>

    <!-- Logs Tab -->
    <div class="tab-panel" id="tab-logs">
      <div class="logs-container">
        <div class="logs-toolbar">
          <select id="logs-level-filter">
            <option value="all">All Levels</option>
            <option value="ERROR">Error</option>
            <option value="WARN">Warn</option>
            <option value="INFO">Info</option>
            <option value="DEBUG">Debug</option>
          </select>
          <input type="text" id="logs-target-filter" placeholder="Filter by target...">
          <label class="logs-checkbox"><input type="checkbox" id="logs-autoscroll" checked> Auto-scroll</label>
          <button id="logs-pause-btn" onclick="toggleLogsPause()">Pause</button>
          <button onclick="clearLogs()">Clear</button>
        </div>
        <div class="logs-output" id="logs-output"></div>
      </div>
    </div>

    <!-- Routines Tab -->
    <div class="tab-panel" id="tab-routines">
      <div class="routines-container">
        <div class="routines-summary" id="routines-summary"></div>
        <table class="routines-table" id="routines-table">
          <thead>
            <tr>
              <th>Name</th>
              <th>Trigger</th>
              <th>Action</th>
              <th>Last Run</th>
              <th>Next Run</th>
              <th>Runs</th>
              <th>Status</th>
              <th>Actions</th>
            </tr>
          </thead>
          <tbody id="routines-tbody"></tbody>
        </table>
        <div class="empty-state" id="routines-empty" style="display:none">
          No routines configured. Ask the assistant to create one.
        </div>
        <div class="routine-detail" id="routine-detail" style="display:none"></div>
      </div>
    </div>

    <!-- Extensions Tab -->
    <div class="tab-panel" id="tab-extensions">
      <div class="extensions-container">
        <div class="extensions-section">
          <h3>Install Extension</h3>
          <div class="ext-install-form" id="ext-install-form">
            <input type="text" id="ext-install-name" placeholder="Extension name (required)">
            <input type="text" id="ext-install-url" placeholder="URL (optional)">
            <select id="ext-install-kind">
              <option value="mcp_server">MCP Server</option>
              <option value="wasm_tool">WASM Tool</option>
              <option value="wasm_channel">WASM Channel</option>
            </select>
            <button onclick="installExtension()">Install</button>
          </div>
        </div>
        <div class="extensions-section">
          <h3>Installed Extensions</h3>
          <div class="extensions-list" id="extensions-list">
            <div class="empty-state">Loading extensions...</div>
          </div>
        </div>
        <div class="extensions-section">
          <h3>Registered Tools</h3>
          <table class="tools-table" id="tools-table">
            <thead>
              <tr>
                <th>Name</th>
                <th>Description</th>
              </tr>
            </thead>
            <tbody id="tools-tbody"></tbody>
          </table>
          <div class="empty-state" id="tools-empty" style="display:none">No tools registered</div>
        </div>
      </div>
    </div>
  </div>

  <div id="toasts"></div>
  <script src="/app.js"></script>
</body>
</html>