chore: comprehensive branding scrub from Hermes audit — electron, tauri, env, local-setup, docs archived

Fixes from Hermes Agent gpt-5.4 audit:
- Electron builder: appId/productName/copyright → Hermes Workspace
- Tauri: bundle identifier → com.hermes.workspace
- Electron preload: window.clawsuite → window.hermesWorkspace
- Electron onboarding: npm install openclaw → pip install hermes-agent
- Env vars: CLAWDBOT_*/CLAWSUITE_* → HERMES_*
- local-setup.ts: full Hermes rewrite (install, start, config paths)
- workspace/files API: .openclaw → .hermes paths
- Legacy ClawSuite docs → docs/archive/
- README: openclaw.ai → github.com/NousResearch/hermes-agent
- .workspace-source updated
This commit is contained in:
outsourc-e
2026-03-15 23:43:13 -04:00
parent dffdb4dc12
commit 45af81b657
22 changed files with 62 additions and 62 deletions

View File

@@ -1,6 +1,6 @@
# ClawSuite → OpenClaw Gateway Connection
# Hermes Workspace → Hermes Gateway Connection
#
# The ClawSuite server connects to the OpenClaw Gateway via WebSocket.
# The Hermes Workspace server connects to the Hermes Gateway via WebSocket.
# Keep secrets here (never exposed to the browser).
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
@@ -11,7 +11,7 @@
# - Local gateway (default): ws://127.0.0.1:18789
# - Remote gateway: wss://your-gateway.example.com
# - Docker: ws://host.docker.internal:18789 (to reach host machine)
CLAWDBOT_GATEWAY_URL=ws://127.0.0.1:18789
HERMES_GATEWAY_URL=ws://127.0.0.1:18789
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# AUTHENTICATION (Choose one method)
@@ -20,22 +20,22 @@ CLAWDBOT_GATEWAY_URL=ws://127.0.0.1:18789
# Gateway Token (Recommended)
# How to find your token:
# 1. Run: openclaw config get gateway.auth.token
# 2. Or check OpenClaw settings UI
# 2. Or check Hermes settings UI
# Format: clw_abc123def456... (64+ characters)
CLAWDBOT_GATEWAY_TOKEN=
HERMES_GATEWAY_TOKEN=
# Gateway Password (Alternative to token)
# Only use if your gateway is configured for password auth
# CLAWDBOT_GATEWAY_PASSWORD=
# HERMES_GATEWAY_PASSWORD=
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# CLAWSUITE ACCESS CONTROL (Optional)
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# Password-protect ClawSuite web interface
# Password-protect Hermes Workspace web interface
# Leave empty for no authentication (default for local use)
# Set this for production deployments
# CLAWSUITE_PASSWORD=
# HERMES_PASSWORD=
# Allow access from non-localhost addresses
# Comma-separated list of hostnames/IPs
@@ -44,4 +44,4 @@ CLAWDBOT_GATEWAY_TOKEN=
# - Tailscale: my-server.tail1234.ts.net
# - LAN: 192.168.1.50
# - Subnet: 192.168.1.0/24
# CLAWSUITE_ALLOWED_HOSTS=
# HERMES_ALLOWED_HOSTS=

View File

@@ -1 +1 @@
/Users/aurora/.openclaw/workspace/clawsuite
/Users/aurora/.openclaw/workspace/hermes-workspace/clawsuite

View File

@@ -65,7 +65,7 @@
### Prerequisites
- **Node.js 22+** — [nodejs.org](https://nodejs.org/)
- **Hermes Agent** running locally — [Setup Guide](https://openclaw.ai/docs/installation)
- **Hermes Agent** running locally — [Setup Guide](https://github.com/NousResearch/hermes-agent)
### Install & Run

View File

@@ -3,9 +3,9 @@
* https://www.electron.build/configuration
*/
module.exports = {
appId: 'com.clawsuite.app',
productName: 'ClawSuite',
copyright: 'Copyright © 2026 ClawSuite',
appId: 'com.hermes.workspace',
productName: 'Hermes Workspace',
copyright: 'Copyright © 2026 Hermes Workspace',
directories: {
output: 'release',
@@ -35,7 +35,7 @@ module.exports = {
},
dmg: {
title: 'ClawSuite',
title: 'Hermes Workspace',
iconSize: 80,
contents: [
{ x: 130, y: 220 },
@@ -68,7 +68,7 @@ module.exports = {
publish: {
provider: 'github',
owner: 'outsourc-e',
repo: 'clawsuite',
repo: 'hermes-workspace',
releaseType: 'release',
},

View File

@@ -121,15 +121,15 @@ function findRunningServer() {
function findRepoDir() {
// Common locations for the Hermes Workspace repo
const candidates = [
(0, path_1.join)(process.env.HOME || '', '.openclaw', 'workspace', 'clawsuite'),
(0, path_1.join)(process.env.HOME || '', 'clawsuite'),
(0, path_1.join)(process.env.HOME || '', '.openclaw', 'workspace', 'hermesWorkspace'),
(0, path_1.join)(process.env.HOME || '', 'hermesWorkspace'),
(0, path_1.join)(__dirname, '..'),
];
for (const dir of candidates) {
if ((0, fs_1.existsSync)((0, path_1.join)(dir, 'package.json'))) {
try {
const pkg = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(dir, 'package.json'), 'utf-8'));
if (pkg.name === 'clawsuite' || pkg.name === '@clawsuite/app') return dir;
if (pkg.name === 'hermesWorkspace' || pkg.name === '@clawsuite/app') return dir;
} catch { /* skip */ }
}
}

View File

@@ -396,7 +396,7 @@
<div class="terminal" id="install-terminal"></div>
<div class="actions">
<button class="btn btn-secondary" onclick="goToStep(1)">← Back</button>
<button class="btn btn-primary" id="install-btn" onclick="installOpenClaw()">Install & Start</button>
<button class="btn btn-primary" id="install-btn" onclick="installHermes()">Install & Start</button>
</div>
`
} else if (selectedMode === 'cloud') {
@@ -425,7 +425,7 @@
status.innerHTML = '<div class="spinner"></div> Checking for Hermes...'
try {
const result = await window.clawsuite.gateway.check()
const result = await window.hermesWorkspace.gateway.check()
if (result.url) {
document.getElementById('gateway-url').value = result.url
status.className = 'status show status-success'
@@ -447,7 +447,7 @@
status.innerHTML = '<div class="spinner"></div> Connecting...'
try {
const result = await window.clawsuite.gateway.connect(url)
const result = await window.hermesWorkspace.gateway.connect(url)
if (result.success) {
gatewayUrl = url
status.className = 'status show status-success'
@@ -470,7 +470,7 @@
}
}
async function installOpenClaw() {
async function installHermes() {
const status = document.getElementById('install-status')
const terminal = document.getElementById('install-terminal')
const btn = document.getElementById('install-btn')
@@ -480,16 +480,16 @@
status.className = 'status show status-loading'
status.innerHTML = '<div class="spinner"></div> Installing Hermes Agent...'
terminal.classList.add('show')
terminal.textContent = '$ npm install -g openclaw\n'
terminal.textContent = '$ pip install hermes-agent\n'
try {
const result = await window.clawsuite.gateway.install()
const result = await window.hermesWorkspace.gateway.install()
terminal.textContent += result.output + '\n✓ Installed!\n\n'
status.innerHTML = '<div class="spinner"></div> Starting Hermes...'
terminal.textContent += '$ openclaw gateway start\n'
terminal.textContent += '$ hermes --web\n'
const startResult = await window.clawsuite.gateway.start()
const startResult = await window.hermesWorkspace.gateway.start()
if (startResult.success) {
gatewayUrl = startResult.url
status.className = 'status show status-success'
@@ -507,7 +507,7 @@
}
} catch (e) {
status.className = 'status show status-error'
status.innerHTML = '✗ Installation failed. Try running manually: npm install -g openclaw'
status.innerHTML = '✗ Installation failed. Try running manually: pip install hermes-agent'
terminal.textContent += '✗ Error: ' + e.message + '\n'
btn.disabled = false
btn.textContent = 'Retry'
@@ -525,7 +525,7 @@
async function finishSetup() {
if (gatewayUrl) {
await window.clawsuite.onboarding.complete({
await window.hermesWorkspace.onboarding.complete({
mode: selectedMode,
gatewayUrl: gatewayUrl,
})

View File

@@ -5,7 +5,7 @@
*/
Object.defineProperty(exports, "__esModule", { value: true });
const electron_1 = require("electron");
electron_1.contextBridge.exposeInMainWorld('clawsuite', {
electron_1.contextBridge.exposeInMainWorld('hermesWorkspace', {
// Gateway management
gateway: {
check: () => electron_1.ipcRenderer.invoke('gateway:check'),

View File

@@ -5,7 +5,7 @@
import { contextBridge, ipcRenderer } from 'electron'
contextBridge.exposeInMainWorld('clawsuite', {
contextBridge.exposeInMainWorld('hermesWorkspace', {
// Gateway management
gateway: {
check: () => ipcRenderer.invoke('gateway:check'),

View File

@@ -2,7 +2,7 @@
"$schema": "https://schema.tauri.app/config/2",
"productName": "Hermes Workspace",
"version": "3.2.0",
"identifier": "io.buildingthefuture.clawsuite",
"identifier": "com.hermes.workspace",
"build": {
"frontendDist": "../dist/client",
"devUrl": "http://localhost:3000",

View File

@@ -154,7 +154,7 @@ function readSavedGatewayConfig(): SavedGatewayConfig | null {
try {
const settingsRaw =
localStorage.getItem('hermes-settings') ??
localStorage.getItem('openclaw-settings')
localStorage.getItem('hermes-settings')
if (settingsRaw) {
const parsed = JSON.parse(settingsRaw) as {
state?: { settings?: { gatewayUrl?: string; gatewayToken?: string } }

View File

@@ -22,7 +22,7 @@ type SetupEvent = {
token?: string
}
type OpenClawConfig = {
type HermesConfig = {
gateway?: {
port?: number
auth?: {
@@ -87,9 +87,9 @@ async function runCommand(command: string, args: string[], timeoutMs: number) {
)
}
async function isOpenClawInstalled() {
async function isHermesInstalled() {
try {
const whichResult = await runCommand('which', ['openclaw'], 5_000)
const whichResult = await runCommand('which', ['hermes'], 5_000)
if (whichResult.code === 0 && whichResult.stdout.trim()) {
return true
}
@@ -98,15 +98,15 @@ async function isOpenClawInstalled() {
}
try {
const versionResult = await runCommand('openclaw', ['--version'], 5_000)
const versionResult = await runCommand('hermes', ['--version'], 5_000)
return versionResult.code === 0 && Boolean(versionResult.stdout.trim())
} catch {
return false
}
}
async function installOpenClaw() {
const result = await runCommand('npm', ['install', '-g', 'openclaw'], 10 * 60_000)
async function installHermes() {
const result = await runCommand('pip', ['install', 'hermes-agent'], 10 * 60_000)
if (result.code !== 0) {
throw new Error(result.stderr.trim() || result.stdout.trim() || 'npm install failed')
}
@@ -136,13 +136,13 @@ async function isGatewayRunning(port: number) {
})
}
async function readGatewayConfig(): Promise<OpenClawConfig | null> {
async function readGatewayConfig(): Promise<HermesConfig | null> {
const configPath = join(homedir(), '.openclaw', 'openclaw.json')
try {
await access(configPath)
const raw = await readFile(configPath, 'utf8')
return JSON.parse(raw) as OpenClawConfig
return JSON.parse(raw) as HermesConfig
} catch {
return null
}
@@ -183,7 +183,7 @@ async function waitForGatewayToken() {
await wait(POLL_INTERVAL_MS)
}
throw new Error('Gateway auth token was not written to ~/.openclaw/openclaw.json')
throw new Error('Gateway auth token was not written to ~/.hermes/config.yaml')
}
export const Route = createFileRoute('/api/local-setup')({
@@ -243,14 +243,14 @@ export const Route = createFileRoute('/api/local-setup')({
message: 'Checking for Hermes...',
})
let installed = await isOpenClawInstalled()
let installed = await isHermesInstalled()
if (!installed) {
emit({
status: 'installing',
message: 'Installing Hermes...',
})
await installOpenClaw()
installed = await isOpenClawInstalled()
await installHermes()
installed = await isHermesInstalled()
}
if (!installed) {
@@ -271,7 +271,7 @@ export const Route = createFileRoute('/api/local-setup')({
} catch (error) {
throw new Error(
formatCommandError(
'openclaw gateway start --bind lan',
'hermes --web',
error,
'Failed to launch the Hermes gateway',
),

View File

@@ -40,13 +40,13 @@ type ConnectParams = {
}
function getGatewayConfig() {
const url = process.env.CLAWDBOT_GATEWAY_URL?.trim() || 'ws://127.0.0.1:18789'
const token = process.env.CLAWDBOT_GATEWAY_TOKEN?.trim() || ''
const password = process.env.CLAWDBOT_GATEWAY_PASSWORD?.trim() || ''
const url = process.env.HERMES_GATEWAY_URL?.trim() || 'ws://127.0.0.1:18789'
const token = process.env.HERMES_GATEWAY_TOKEN?.trim() || ''
const password = process.env.HERMES_GATEWAY_PASSWORD?.trim() || ''
if (!token && !password) {
throw new Error(
'Missing gateway auth. Set CLAWDBOT_GATEWAY_TOKEN (recommended) or CLAWDBOT_GATEWAY_PASSWORD in the server environment.',
'Missing gateway auth. Set HERMES_GATEWAY_TOKEN (recommended) or HERMES_GATEWAY_PASSWORD in the server environment.',
)
}

View File

@@ -58,7 +58,7 @@ async function detectWorkspace(savedPath?: string): Promise<{
}
// Priority 3: Default Hermes workspace path
const defaultPath = path.join(os.homedir(), '.openclaw', 'workspace')
const defaultPath = path.join(os.homedir(), '.hermes')
const defaultValid = await isValidDirectory(defaultPath)
if (defaultValid) {
return {
@@ -75,7 +75,7 @@ async function detectWorkspace(savedPath?: string): Promise<{
if (openclawValid) {
return {
path: openclawDir,
folderName: '.openclaw',
folderName: '.hermes',
source: 'default',
isValid: true,
}

View File

@@ -29,7 +29,7 @@ type DateStampedFile = {
function getWorkspaceRoot(): string {
const configured = (process.env.OPENCLAW_WORKSPACE || '').trim()
return path.resolve(
configured || path.join(os.homedir(), '.openclaw', 'workspace'),
configured || path.join(os.homedir(), '.hermes'),
)
}

View File

@@ -61,7 +61,7 @@ const OPENAI_MODEL = 'gpt-4o-mini'
function getGatewayHttpUrl(path: string): string {
const envUrl =
process.env.CLAWDBOT_GATEWAY_URL?.trim() || 'ws://127.0.0.1:18789'
process.env.HERMES_GATEWAY_URL?.trim() || 'ws://127.0.0.1:18789'
try {
const parsed = new URL(envUrl)
parsed.protocol = parsed.protocol === 'wss:' ? 'https:' : 'http:'
@@ -143,7 +143,7 @@ async function readHermesConfig(): Promise<HermesConfig | null> {
async function resolveProvider(): Promise<ResolvedProvider | null> {
// Try gateway first — works with any configured provider, uses gateway token
try {
const gwTokenEnv = process.env.CLAWDBOT_GATEWAY_TOKEN?.trim()
const gwTokenEnv = process.env.HERMES_GATEWAY_TOKEN?.trim()
if (gwTokenEnv) {
// Quick probe to see if gateway is up
const probe = await fetch(getGatewayHttpUrl('/health'), {

View File

@@ -105,9 +105,9 @@ async function discoverFromCli(): Promise<DiscoveryResult> {
* Check if env vars are already set
*/
function discoverFromEnv(): DiscoveryResult {
const url = process.env.CLAWDBOT_GATEWAY_URL?.trim()
const token = process.env.CLAWDBOT_GATEWAY_TOKEN?.trim()
const password = process.env.CLAWDBOT_GATEWAY_PASSWORD?.trim()
const url = process.env.HERMES_GATEWAY_URL?.trim()
const token = process.env.HERMES_GATEWAY_TOKEN?.trim()
const password = process.env.HERMES_GATEWAY_PASSWORD?.trim()
if (token) {
// Only short-circuit if we actually have a token.
@@ -253,16 +253,16 @@ export async function discoverGateway(): Promise<DiscoveryResult> {
const fileResult = await discoverFromConfigFile()
if (fileResult.found) {
// Apply to process.env so gateway client uses it
if (fileResult.url) process.env.CLAWDBOT_GATEWAY_URL = fileResult.url
if (fileResult.token) process.env.CLAWDBOT_GATEWAY_TOKEN = fileResult.token
if (fileResult.url) process.env.HERMES_GATEWAY_URL = fileResult.url
if (fileResult.token) process.env.HERMES_GATEWAY_TOKEN = fileResult.token
return fileResult
}
// 3. Try CLI (slower, but works if config file structure differs)
const cliResult = await discoverFromCli()
if (cliResult.found) {
if (cliResult.url) process.env.CLAWDBOT_GATEWAY_URL = cliResult.url
if (cliResult.token) process.env.CLAWDBOT_GATEWAY_TOKEN = cliResult.token
if (cliResult.url) process.env.HERMES_GATEWAY_URL = cliResult.url
if (cliResult.token) process.env.HERMES_GATEWAY_TOKEN = cliResult.token
return cliResult
}