From 4d6eec741dc74794c99059264face4d317aa50bc Mon Sep 17 00:00:00 2001
From: kumarabhirup
- Website · Docs · OpenClaw Framework · Discord · Skills Store + Website · Docs · OpenClaw Framework · Discord · Skills Store
--- @@ -35,7 +35,7 @@ ```bash npm i -g openclaw -npx ironclaw +npx denchclaw ``` Opens at `localhost:3100`. That's it. @@ -44,15 +44,15 @@ Three steps total: ``` 1. npm i -g openclaw -2. npx ironclaw +2. npx denchclaw 3. bootstrap opens UI on localhost:3100 ``` --- -## What is Ironclaw? +## What is DenchClaw? -Ironclaw is a personal AI agent and CRM that runs locally on your machine. It connects to every messaging channel you use, manages structured data through DuckDB, browses the web with your Chrome profile, and gives you a full web UI for pipeline management, analytics, and document management. +DenchClaw is a personal AI agent and CRM that runs locally on your machine. It connects to every messaging channel you use, manages structured data through DuckDB, browses the web with your Chrome profile, and gives you a full web UI for pipeline management, analytics, and document management. Built on [OpenClaw](https://github.com/openclaw/openclaw) with **Vercel AI SDK v6** as the LLM orchestration layer. @@ -70,7 +70,7 @@ Built on [OpenClaw](https://github.com/openclaw/openclaw) with **Vercel AI SDK v ### Find Leads -Type a prompt, Ironclaw scrapes the web using your actual Chrome profile (all your auth sessions, cookies, history). It logs into LinkedIn, browses YC batches, pulls company data. No separate login, no API keys for browsing. +Type a prompt, DenchClaw scrapes the web using your actual Chrome profile (all your auth sessions, cookies, history). It logs into LinkedIn, browses YC batches, pulls company data. No separate login, no API keys for browsing. ### Enrich Data @@ -82,7 +82,7 @@ Personalized LinkedIn messages, cold emails, follow-up sequences. Each message i ### Analyze Pipeline -Ask for analytics in plain English. Ironclaw queries your DuckDB workspace and generates interactive Recharts dashboards inline. Pipeline funnels, outreach activity charts, conversion rates, donut breakdowns. +Ask for analytics in plain English. DenchClaw queries your DuckDB workspace and generates interactive Recharts dashboards inline. Pipeline funnels, outreach activity charts, conversion rates, donut breakdowns. ### Automate Everything @@ -94,11 +94,11 @@ Cron jobs that run on schedule. Follow-up if no reply after 3 days. Move leads t ### Uses Your Chrome Profile -Unlike other AI tools, Ironclaw copies your existing Chrome profile with all your auth sessions, cookies, and history. It logs into LinkedIn, scrapes YC batches, and sends messages as you. No separate browser login needed. +Unlike other AI tools, DenchClaw copies your existing Chrome profile with all your auth sessions, cookies, and history. It logs into LinkedIn, scrapes YC batches, and sends messages as you. No separate browser login needed. ### Chat with Your Database -Ask questions in plain English. Ironclaw translates to SQL, queries your local DuckDB, and returns structured results. Like having a data analyst on speed dial. +Ask questions in plain English. DenchClaw translates to SQL, queries your local DuckDB, and returns structured results. Like having a data analyst on speed dial. ``` You: "How many founders have we contacted from YC W26?" @@ -111,7 +111,7 @@ Reply rate is 34%. ### Coding Agent with Diffs -Ironclaw writes code. Review changes in a rich diff viewer before applying. Config changes, automation scripts, data transformations. All with diffs you approve. +DenchClaw writes code. Review changes in a rich diff viewer before applying. Config changes, automation scripts, data transformations. All with diffs you approve. ### Your Second Brain @@ -138,18 +138,18 @@ The web app runs at `localhost:3100` and includes: One agent, every channel. Connect any messaging platform. Your AI agent responds everywhere, managed from a single terminal. -| Channel | Setup | -| ------------------- | ------------------------------------------------------------- | -| **WhatsApp** | `ironclaw channels login` + set `channels.whatsapp.allowFrom` | -| **Telegram** | Set `TELEGRAM_BOT_TOKEN` or `channels.telegram.botToken` | -| **Slack** | Set `SLACK_BOT_TOKEN` + `SLACK_APP_TOKEN` | -| **Discord** | Set `DISCORD_BOT_TOKEN` or `channels.discord.token` | -| **Signal** | Requires `signal-cli` + `channels.signal` config | -| **iMessage** | Via BlueBubbles (recommended) or legacy macOS integration | -| **Microsoft Teams** | Configure Teams app + Bot Framework | -| **Google Chat** | Chat API integration | -| **Matrix** | Extension channel | -| **WebChat** | Built-in, uses Gateway WebSocket directly | +| Channel | Setup | +| ------------------- | -------------------------------------------------------------- | +| **WhatsApp** | `denchclaw channels login` + set `channels.whatsapp.allowFrom` | +| **Telegram** | Set `TELEGRAM_BOT_TOKEN` or `channels.telegram.botToken` | +| **Slack** | Set `SLACK_BOT_TOKEN` + `SLACK_APP_TOKEN` | +| **Discord** | Set `DISCORD_BOT_TOKEN` or `channels.discord.token` | +| **Signal** | Requires `signal-cli` + `channels.signal` config | +| **iMessage** | Via BlueBubbles (recommended) or legacy macOS integration | +| **Microsoft Teams** | Configure Teams app + Bot Framework | +| **Google Chat** | Chat API integration | +| **Matrix** | Extension channel | +| **WebChat** | Built-in, uses Gateway WebSocket directly | ``` WhatsApp · Telegram · Slack · Discord @@ -157,7 +157,7 @@ One agent, every channel. Connect any messaging platform. Your AI agent responds │ ▼ ┌────────────────────────────┐ - │ Ironclaw Gateway │ + │ DenchClaw Gateway │ │ ws://127.0.0.1:18789 │ └─────────────┬──────────────┘ │ @@ -165,7 +165,7 @@ One agent, every channel. Connect any messaging platform. Your AI agent responds │ │ │ ▼ ▼ ▼ AI SDK Web UI CLI - Engine (Dench) (ironclaw) + Engine (Dench) (denchclaw) ``` --- @@ -217,7 +217,7 @@ Reports use the `report-json` format and render inline in chat as interactive Re ## Kanban Pipeline -Drag-and-drop kanban boards that auto-update as leads reply. Ironclaw moves cards through your pipeline automatically. +Drag-and-drop kanban boards that auto-update as leads reply. DenchClaw moves cards through your pipeline automatically. Columns like New Lead → Contacted → Qualified → Demo Scheduled → Closed map to your sales process. Each card shows the lead name, company, and last action taken. @@ -243,7 +243,7 @@ Scheduled automations that run in the background: | CRM backup to S3 | `0 2 * * *` | Nightly workspace backup | ```bash -ironclaw cron list +denchclaw cron list ``` --- @@ -267,9 +267,9 @@ The Gateway is the local-first WebSocket control plane that routes everything: ### Security - **DM pairing** enabled by default. Unknown senders get a pairing code. -- Approve with `ironclaw pairing approve`
+- Approve with `denchclaw pairing approve `
- Non-main sessions can be sandboxed in Docker
-- Run `ironclaw doctor` to audit DM policies
+- Run `denchclaw doctor` to audit DM policies
---
@@ -329,22 +329,22 @@ Features:
```bash
# Install
-npm i -g ironclaw
+npm i -g denchclaw
# Run onboarding wizard
-ironclaw onboard --install-daemon
+denchclaw onboard --install-daemon
# Start the gateway
-ironclaw gateway start
+denchclaw gateway start
# Open the web UI
open http://localhost:3100
# Talk to your agent from CLI
-ironclaw agent --message "Summarize my inbox" --thinking high
+denchclaw agent --message "Summarize my inbox" --thinking high
# Send a message
-ironclaw message send --to +1234567890 --message "Hello from Ironclaw"
+denchclaw message send --to +1234567890 --message "Hello from DenchClaw"
```
---
@@ -352,8 +352,8 @@ ironclaw message send --to +1234567890 --message "Hello from Ironclaw"
## From Source
```bash
-git clone https://github.com/kumarabhirup/ironclaw.git
-cd ironclaw
+git clone https://github.com/kumarabhirup/denchclaw.git
+cd denchclaw
pnpm install
pnpm build
@@ -402,7 +402,7 @@ pnpm dev # Dev mode (auto-reload)
## Upstream
-Ironclaw is built on [OpenClaw](https://github.com/openclaw/openclaw). To sync with upstream:
+DenchClaw is built on [OpenClaw](https://github.com/openclaw/openclaw). To sync with upstream:
```bash
git remote add upstream https://github.com/openclaw/openclaw.git
@@ -416,8 +416,8 @@ git merge upstream/main
MIT Licensed. Fork it, extend it, make it yours.
-[](https://www.star-history.com/?repos=denchHQ%2Fironclaw&type=date&legend=top-left)
+[](https://www.star-history.com/?repos=denchHQ%2Fdenchclaw&type=date&legend=top-left)
diff --git a/apps/web/app/api/profiles/route.test.ts b/apps/web/app/api/profiles/route.test.ts
index 010031c35ae..8ab5d8d7bda 100644
--- a/apps/web/app/api/profiles/route.test.ts
+++ b/apps/web/app/api/profiles/route.test.ts
@@ -3,7 +3,7 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
vi.mock("@/lib/workspace", () => ({
discoverWorkspaces: vi.fn(() => []),
getActiveWorkspaceName: vi.fn(() => null),
- resolveOpenClawStateDir: vi.fn(() => "/home/testuser/.openclaw-ironclaw"),
+ resolveOpenClawStateDir: vi.fn(() => "/home/testuser/.openclaw-dench"),
resolveWorkspaceRoot: vi.fn(() => null),
setUIActiveWorkspace: vi.fn(),
}));
@@ -18,7 +18,7 @@ vi.mock("node:fs", () => ({
describe("profiles API", () => {
const originalEnv = { ...process.env };
- const STATE_DIR = "/home/testuser/.openclaw-ironclaw";
+ const STATE_DIR = "/home/testuser/.openclaw-dench";
beforeEach(() => {
vi.resetModules();
diff --git a/apps/web/app/api/workspace/delete/route.test.ts b/apps/web/app/api/workspace/delete/route.test.ts
index 68253e8aaa5..8f65606c870 100644
--- a/apps/web/app/api/workspace/delete/route.test.ts
+++ b/apps/web/app/api/workspace/delete/route.test.ts
@@ -51,7 +51,7 @@ describe("POST /api/workspace/delete", () => {
vi.mocked(workspace.discoverWorkspaces).mockReturnValue([
{
name: "work",
- stateDir: "/home/testuser/.openclaw-ironclaw",
+ stateDir: "/home/testuser/.openclaw-dench",
workspaceDir: null,
isActive: false,
hasConfig: true,
@@ -65,13 +65,13 @@ describe("POST /api/workspace/delete", () => {
it("deletes workspace directory directly via rmSync", async () => {
const workspace = await import("@/lib/workspace");
const { rmSync } = await import("node:fs");
- const workspaceDir = "/home/testuser/.openclaw-ironclaw/workspace-work";
+ const workspaceDir = "/home/testuser/.openclaw-dench/workspace-work";
vi.mocked(workspace.discoverWorkspaces)
.mockReturnValueOnce([
{
name: "work",
- stateDir: "/home/testuser/.openclaw-ironclaw",
+ stateDir: "/home/testuser/.openclaw-dench",
workspaceDir,
isActive: true,
hasConfig: true,
@@ -98,12 +98,12 @@ describe("POST /api/workspace/delete", () => {
it("returns 500 when rmSync fails", async () => {
const workspace = await import("@/lib/workspace");
const { rmSync } = await import("node:fs");
- const workspaceDir = "/home/testuser/.openclaw-ironclaw/workspace-work";
+ const workspaceDir = "/home/testuser/.openclaw-dench/workspace-work";
vi.mocked(workspace.discoverWorkspaces).mockReturnValue([
{
name: "work",
- stateDir: "/home/testuser/.openclaw-ironclaw",
+ stateDir: "/home/testuser/.openclaw-dench",
workspaceDir,
isActive: false,
hasConfig: true,
diff --git a/apps/web/app/api/workspace/init/route.test.ts b/apps/web/app/api/workspace/init/route.test.ts
index 9090df75864..5ac5ef1e628 100644
--- a/apps/web/app/api/workspace/init/route.test.ts
+++ b/apps/web/app/api/workspace/init/route.test.ts
@@ -1,7 +1,7 @@
import { join } from "node:path";
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
-const STATE_DIR = "/home/testuser/.openclaw-ironclaw";
+const STATE_DIR = "/home/testuser/.openclaw-dench";
vi.mock("node:fs", () => ({
existsSync: vi.fn(() => false),
@@ -17,12 +17,13 @@ vi.mock("@/lib/workspace", () => ({
discoverWorkspaces: vi.fn(() => []),
setUIActiveWorkspace: vi.fn(),
getActiveWorkspaceName: vi.fn(() => "work"),
- resolveOpenClawStateDir: vi.fn(() => "/home/testuser/.openclaw-ironclaw"),
+ resolveOpenClawStateDir: vi.fn(() => "/home/testuser/.openclaw-dench"),
resolveWorkspaceDirForName: vi.fn((name: string) =>
- join("/home/testuser/.openclaw-ironclaw", `workspace-${name}`),
+ join("/home/testuser/.openclaw-dench", `workspace-${name}`),
),
isValidWorkspaceName: vi.fn(() => true),
resolveWorkspaceRoot: vi.fn(() => null),
+ ensureAgentInConfig: vi.fn(),
}));
describe("POST /api/workspace/init", () => {
@@ -83,7 +84,7 @@ describe("POST /api/workspace/init", () => {
expect(response.status).toBe(409);
});
- it("creates workspace directory at ~/.openclaw-ironclaw/workspace- (enforces fixed layout)", async () => {
+ it("creates workspace directory at ~/.openclaw-dench/workspace- (enforces fixed layout)", async () => {
const { mkdirSync, writeFileSync } = await import("node:fs");
const workspace = await import("@/lib/workspace");
vi.mocked(workspace.discoverWorkspaces).mockReturnValue([]);
@@ -158,7 +159,7 @@ describe("POST /api/workspace/init", () => {
const raw = identityWrites[identityWrites.length - 1][1];
const identityContent = typeof raw === "string" ? raw : JSON.stringify(raw);
expect(identityContent).toContain(expectedSkillPath);
- expect(identityContent).toContain("Ironclaw");
+ expect(identityContent).toContain("DenchClaw");
expect(identityContent).not.toContain("~skills");
});
});
diff --git a/apps/web/app/api/workspace/init/route.ts b/apps/web/app/api/workspace/init/route.ts
index 46ed5200639..537e492c4e3 100644
--- a/apps/web/app/api/workspace/init/route.ts
+++ b/apps/web/app/api/workspace/init/route.ts
@@ -17,7 +17,7 @@ import {
} from "@/lib/workspace";
import {
seedWorkspaceFromAssets,
- buildIronclawIdentity,
+ buildDenchClawIdentity,
} from "@repo/cli/workspace-seed";
export const dynamic = "force-dynamic";
@@ -108,7 +108,7 @@ export async function POST(req: Request) {
}
if (body.path?.trim()) {
return Response.json(
- { error: "Custom workspace paths are currently disabled. Workspaces are created in ~/.openclaw-ironclaw." },
+ { error: "Custom workspace paths are currently disabled. Workspaces are created in ~/.openclaw-dench." },
{ status: 400 },
);
}
@@ -163,7 +163,7 @@ export async function POST(req: Request) {
}
}
- // Seed managed skills, Ironclaw identity, DuckDB, and CRM object projections.
+ // Seed managed skills, DenchClaw identity, DuckDB, and CRM object projections.
// This is the single source of truth shared with the CLI bootstrap path.
if (projectRoot) {
const seedResult = seedWorkspaceFromAssets({ workspaceDir, packageRoot: projectRoot });
@@ -173,10 +173,10 @@ export async function POST(req: Request) {
}
} else {
// No project root available (e.g. standalone/production build without
- // the repo tree). Still write the Ironclaw identity so the agent has
+ // the repo tree). Still write the DenchClaw identity so the agent has
// a usable IDENTITY.md.
const identityPath = join(workspaceDir, "IDENTITY.md");
- writeFileSync(identityPath, buildIronclawIdentity(workspaceDir) + "\n", "utf-8");
+ writeFileSync(identityPath, buildDenchClawIdentity(workspaceDir) + "\n", "utf-8");
seeded.push("IDENTITY.md");
}
diff --git a/apps/web/app/api/workspace/thumbnail/route.ts b/apps/web/app/api/workspace/thumbnail/route.ts
index 22b298ead14..89c832b4e8f 100644
--- a/apps/web/app/api/workspace/thumbnail/route.ts
+++ b/apps/web/app/api/workspace/thumbnail/route.ts
@@ -8,7 +8,7 @@ import { safeResolvePath } from "@/lib/workspace";
export const dynamic = "force-dynamic";
export const runtime = "nodejs";
-const THUMB_DIR = join(tmpdir(), "ironclaw-thumbs");
+const THUMB_DIR = join(tmpdir(), "denchclaw-thumbs");
mkdirSync(THUMB_DIR, { recursive: true });
/**
diff --git a/apps/web/app/api/workspace/tree-browse.test.ts b/apps/web/app/api/workspace/tree-browse.test.ts
index 083fd6cb9b9..d62e396d956 100644
--- a/apps/web/app/api/workspace/tree-browse.test.ts
+++ b/apps/web/app/api/workspace/tree-browse.test.ts
@@ -17,7 +17,7 @@ vi.mock("node:os", () => ({
// Mock workspace
vi.mock("@/lib/workspace", () => ({
resolveWorkspaceRoot: vi.fn(() => null),
- resolveOpenClawStateDir: vi.fn(() => "/home/testuser/.openclaw-ironclaw"),
+ resolveOpenClawStateDir: vi.fn(() => "/home/testuser/.openclaw-dench"),
getActiveWorkspaceName: vi.fn(() => null),
parseSimpleYaml: vi.fn(() => ({})),
duckdbQueryAll: vi.fn(() => []),
@@ -57,7 +57,7 @@ describe("Workspace Tree & Browse API", () => {
}));
vi.mock("@/lib/workspace", () => ({
resolveWorkspaceRoot: vi.fn(() => null),
- resolveOpenClawStateDir: vi.fn(() => "/home/testuser/.openclaw-ironclaw"),
+ resolveOpenClawStateDir: vi.fn(() => "/home/testuser/.openclaw-dench"),
getActiveWorkspaceName: vi.fn(() => null),
parseSimpleYaml: vi.fn(() => ({})),
duckdbQueryAll: vi.fn(() => []),
diff --git a/apps/web/app/components/cron/cron-dashboard.tsx b/apps/web/app/components/cron/cron-dashboard.tsx
index e21a5270767..e3405a3b679 100644
--- a/apps/web/app/components/cron/cron-dashboard.tsx
+++ b/apps/web/app/components/cron/cron-dashboard.tsx
@@ -197,7 +197,7 @@ export function CronDashboard({
}}
>
- No cron jobs configured. Use ironclaw cron add to create one.
+ No cron jobs configured. Use denchclaw cron add to create one.
) : (
diff --git a/apps/web/app/components/sidebar.tsx b/apps/web/app/components/sidebar.tsx
index c0a6b42dd33..57a886e1b64 100644
--- a/apps/web/app/components/sidebar.tsx
+++ b/apps/web/app/components/sidebar.tsx
@@ -406,7 +406,7 @@ export function Sidebar({
- Ironclaw
+ DenchClaw
diff --git a/apps/web/app/components/workspace/empty-state.tsx b/apps/web/app/components/workspace/empty-state.tsx
index 7fe6c43a858..fa6dc4a37bb 100644
--- a/apps/web/app/components/workspace/empty-state.tsx
+++ b/apps/web/app/components/workspace/empty-state.tsx
@@ -89,7 +89,7 @@ export function EmptyState({
) : (
<>
The workspace directory was not
- found. Run the ironclaw bootstrap flow or start a
+ found. Run the denchclaw bootstrap flow or start a
conversation and the agent will set it up
automatically in the managed profile.
>
@@ -136,7 +136,7 @@ export function EmptyState({
>
{expectedPath
? shortenPath(expectedPath)
- : "~/.openclaw-ironclaw/workspace-"}
+ : "~/.openclaw-dench/workspace-"}
diff --git a/apps/web/app/components/workspace/profile-switcher.test.tsx b/apps/web/app/components/workspace/profile-switcher.test.tsx
index dc00fa3f617..5ca46d9e29f 100644
--- a/apps/web/app/components/workspace/profile-switcher.test.tsx
+++ b/apps/web/app/components/workspace/profile-switcher.test.tsx
@@ -129,15 +129,15 @@ describe("ProfileSwitcher workspace delete action", () => {
workspaces: [
{
name: "ghost",
- stateDir: "/home/testuser/.openclaw-ironclaw",
+ stateDir: "/home/testuser/.openclaw-dench",
workspaceDir: null,
isActive: true,
hasConfig: true,
},
{
- name: "ironclaw",
- stateDir: "/home/testuser/.openclaw-ironclaw",
- workspaceDir: "/home/testuser/.openclaw-ironclaw/workspace",
+ name: "dench",
+ stateDir: "/home/testuser/.openclaw-dench",
+ workspaceDir: "/home/testuser/.openclaw-dench/workspace",
isActive: false,
hasConfig: true,
},
@@ -154,12 +154,12 @@ describe("ProfileSwitcher workspace delete action", () => {
});
await waitFor(() => {
- expect(screen.getByText("ironclaw")).toBeInTheDocument();
+ expect(screen.getByText("dench")).toBeInTheDocument();
expect(screen.queryByText("ghost")).not.toBeInTheDocument();
});
await user.click(screen.getByTitle("Switch workspace"));
expect(screen.queryByTitle("Delete workspace ghost")).not.toBeInTheDocument();
- expect(screen.getByTitle("Delete workspace ironclaw")).toBeInTheDocument();
+ expect(screen.getByTitle("Delete workspace dench")).toBeInTheDocument();
});
});
diff --git a/apps/web/app/components/workspace/workspace-sidebar.tsx b/apps/web/app/components/workspace/workspace-sidebar.tsx
index 552d1384951..e6b3834c7e2 100644
--- a/apps/web/app/components/workspace/workspace-sidebar.tsx
+++ b/apps/web/app/components/workspace/workspace-sidebar.tsx
@@ -591,13 +591,13 @@ export function WorkspaceSidebar({
style={{ borderColor: "var(--color-border)" }}
>
- ironclaw.sh
+ denchclaw.sh
{onToggleHidden && (
diff --git a/apps/web/app/layout.tsx b/apps/web/app/layout.tsx
index 2c7f6138995..d5853c5fb85 100644
--- a/apps/web/app/layout.tsx
+++ b/apps/web/app/layout.tsx
@@ -2,7 +2,7 @@ import type { Metadata, Viewport } from "next";
import "./globals.css";
export const metadata: Metadata = {
- title: "Ironclaw",
+ title: "DenchClaw",
description:
"AI Workspace with an agent that connects to your apps and does the work for you",
};
diff --git a/apps/web/app/page.tsx b/apps/web/app/page.tsx
index ea68bd11104..b81e23f503f 100644
--- a/apps/web/app/page.tsx
+++ b/apps/web/app/page.tsx
@@ -37,7 +37,7 @@ const CLAW_ASCII = [
" ░ ░░ ",
];
-const IRONCLAW_ASCII = [
+const DENCHCLAW_ASCII = [
" ██╗██████╗ ██████╗ ███╗ ██╗ ██████╗██╗ █████╗ ██╗ ██╗",
" ██║██╔══██╗██╔═══██╗████╗ ██║██╔════╝██║ ██╔══██╗██║ ██║",
" ██║██████╔╝██║ ██║██╔██╗ ██║██║ ██║ ███████║██║ █╗ ██║",
@@ -103,11 +103,11 @@ export default function Home() {
{/* Foreground content */}
-
- {IRONCLAW_ASCII.join("\n")}
+
+ {DENCHCLAW_ASCII.join("\n")}
- IRONCLAW
+ DENCHCLAW
{
describe("spawnAgentProcess", () => {
it("connects via ws module with Origin header matching the gateway URL (prevents origin rejection)", async () => {
const MockWs = installMockWsModule();
- delete process.env.IRONCLAW_WEB_FORCE_LEGACY_STREAM;
+ delete process.env.DENCHCLAW_WEB_FORCE_LEGACY_STREAM;
const { spawnAgentProcess } = await import("./agent-runner.js");
const proc = spawnAgentProcess("hello", "sess-1");
@@ -298,7 +298,7 @@ describe("agent-runner", () => {
it("sets wss: origin to https: (prevents origin mismatch on TLS gateways)", async () => {
const MockWs = installMockWsModule();
- delete process.env.IRONCLAW_WEB_FORCE_LEGACY_STREAM;
+ delete process.env.DENCHCLAW_WEB_FORCE_LEGACY_STREAM;
process.env.OPENCLAW_GATEWAY_URL = "wss://gateway.example.com:443";
const { spawnAgentProcess } = await import("./agent-runner.js");
@@ -313,7 +313,7 @@ describe("agent-runner", () => {
it("falls back to config gateway port when env port is stale", async () => {
const MockWs = installMockWsModule();
- delete process.env.IRONCLAW_WEB_FORCE_LEGACY_STREAM;
+ delete process.env.DENCHCLAW_WEB_FORCE_LEGACY_STREAM;
process.env.OPENCLAW_GATEWAY_PORT = "19001";
MockWs.failOpenForUrls.add("ws://127.0.0.1:19001/");
@@ -342,7 +342,7 @@ describe("agent-runner", () => {
it("does not use child_process.spawn for WebSocket transport", async () => {
installMockWsModule();
- delete process.env.IRONCLAW_WEB_FORCE_LEGACY_STREAM;
+ delete process.env.DENCHCLAW_WEB_FORCE_LEGACY_STREAM;
const { spawn: mockSpawn } = await import("node:child_process");
vi.mocked(mockSpawn).mockClear();
const { spawnAgentProcess } = await import("./agent-runner.js");
@@ -354,8 +354,8 @@ describe("agent-runner", () => {
proc.kill("SIGTERM");
});
- it("falls back to CLI spawn when IRONCLAW_WEB_FORCE_LEGACY_STREAM is set", async () => {
- process.env.IRONCLAW_WEB_FORCE_LEGACY_STREAM = "1";
+ it("falls back to CLI spawn when DENCHCLAW_WEB_FORCE_LEGACY_STREAM is set", async () => {
+ process.env.DENCHCLAW_WEB_FORCE_LEGACY_STREAM = "1";
const { spawn: mockSpawn } = await import("node:child_process");
const child = mockChildProcess();
vi.mocked(mockSpawn).mockReturnValue(child as unknown as ChildProcess);
@@ -373,7 +373,7 @@ describe("agent-runner", () => {
});
it("includes session-key and lane args in legacy CLI mode", async () => {
- process.env.IRONCLAW_WEB_FORCE_LEGACY_STREAM = "1";
+ process.env.DENCHCLAW_WEB_FORCE_LEGACY_STREAM = "1";
const { spawn: mockSpawn } = await import("node:child_process");
const child = mockChildProcess();
vi.mocked(mockSpawn).mockReturnValue(child as unknown as ChildProcess);
@@ -399,7 +399,7 @@ describe("agent-runner", () => {
describe("spawnAgentSubscribeProcess", () => {
it("subscribes via connect -> sessions.patch -> agent.subscribe", async () => {
const MockWs = installMockWsModule();
- delete process.env.IRONCLAW_WEB_FORCE_LEGACY_STREAM;
+ delete process.env.DENCHCLAW_WEB_FORCE_LEGACY_STREAM;
const { spawnAgentSubscribeProcess } = await import("./agent-runner.js");
const proc = spawnAgentSubscribeProcess("agent:main:web:sess-sub", 12);
@@ -426,7 +426,7 @@ describe("agent-runner", () => {
it("uses payload.globalSeq (not frame seq) for cursor filtering", async () => {
const MockWs = installMockWsModule();
- delete process.env.IRONCLAW_WEB_FORCE_LEGACY_STREAM;
+ delete process.env.DENCHCLAW_WEB_FORCE_LEGACY_STREAM;
const { spawnAgentSubscribeProcess } = await import("./agent-runner.js");
const proc = spawnAgentSubscribeProcess("agent:main:web:sess-gseq", 5);
@@ -489,7 +489,7 @@ describe("agent-runner", () => {
it("keeps subscribe workers alive across lifecycle end events", async () => {
const MockWs = installMockWsModule();
- delete process.env.IRONCLAW_WEB_FORCE_LEGACY_STREAM;
+ delete process.env.DENCHCLAW_WEB_FORCE_LEGACY_STREAM;
const { spawnAgentSubscribeProcess } = await import("./agent-runner.js");
const proc = spawnAgentSubscribeProcess("agent:main:web:sess-sticky", 0);
@@ -545,7 +545,7 @@ describe("agent-runner", () => {
it("drops subscribe events missing a matching session key", async () => {
const MockWs = installMockWsModule();
- delete process.env.IRONCLAW_WEB_FORCE_LEGACY_STREAM;
+ delete process.env.DENCHCLAW_WEB_FORCE_LEGACY_STREAM;
const { spawnAgentSubscribeProcess } = await import("./agent-runner.js");
const proc = spawnAgentSubscribeProcess("agent:main:web:sess-filter", 0);
@@ -602,7 +602,7 @@ describe("agent-runner", () => {
ok: false,
error: { message: "unknown method: agent.subscribe" },
});
- delete process.env.IRONCLAW_WEB_FORCE_LEGACY_STREAM;
+ delete process.env.DENCHCLAW_WEB_FORCE_LEGACY_STREAM;
const { spawnAgentSubscribeProcess } = await import("./agent-runner.js");
const proc = spawnAgentSubscribeProcess("agent:main:web:sess-passive", 0);
@@ -643,7 +643,7 @@ describe("agent-runner", () => {
ok: false,
error: { message: "unknown method: agent.subscribe" },
});
- delete process.env.IRONCLAW_WEB_FORCE_LEGACY_STREAM;
+ delete process.env.DENCHCLAW_WEB_FORCE_LEGACY_STREAM;
const { spawnAgentSubscribeProcess } = await import("./agent-runner.js");
const first = spawnAgentSubscribeProcess("agent:main:web:sess-cache", 0);
diff --git a/apps/web/lib/agent-runner.ts b/apps/web/lib/agent-runner.ts
index bb64c27225d..c7ac38d5114 100644
--- a/apps/web/lib/agent-runner.ts
+++ b/apps/web/lib/agent-runner.ts
@@ -359,10 +359,10 @@ export function buildConnectParams(
version: "dev",
platform: process.platform,
mode: clientMode,
- instanceId: "ironclaw-web-server",
+ instanceId: "denchclaw-web-server",
},
locale: "en-US",
- userAgent: "ironclaw-web",
+ userAgent: "denchclaw-web",
role: "operator",
scopes: ["operator.read", "operator.write", "operator.admin"],
caps,
@@ -880,7 +880,7 @@ class GatewayProcessHandle
}
function shouldForceLegacyStream(): boolean {
- const raw = process.env.IRONCLAW_WEB_FORCE_LEGACY_STREAM?.trim().toLowerCase();
+ const raw = process.env.DENCHCLAW_WEB_FORCE_LEGACY_STREAM?.trim().toLowerCase();
return raw === "1" || raw === "true" || raw === "yes";
}
@@ -1285,7 +1285,7 @@ export async function runAgent(
child.stderr?.on("data", (chunk: Buffer) => {
const text = chunk.toString();
stderrChunks.push(text);
- console.error("[ironclaw stderr]", text);
+ console.error("[denchclaw stderr]", text);
});
});
}
diff --git a/apps/web/lib/workspace-chat-isolation.test.ts b/apps/web/lib/workspace-chat-isolation.test.ts
index 84b027c86c4..dfb4632cd2a 100644
--- a/apps/web/lib/workspace-chat-isolation.test.ts
+++ b/apps/web/lib/workspace-chat-isolation.test.ts
@@ -50,7 +50,7 @@ import { join } from "node:path";
describe("workspace-scoped chat session isolation", () => {
const originalEnv = { ...process.env };
- const STATE_DIR = "/home/testuser/.openclaw-ironclaw";
+ const STATE_DIR = "/home/testuser/.openclaw-dench";
const workspaceDir = (name: string) =>
name === "default"
diff --git a/apps/web/lib/workspace-profiles.test.ts b/apps/web/lib/workspace-profiles.test.ts
index 08549bd9dc0..196cc6f3762 100644
--- a/apps/web/lib/workspace-profiles.test.ts
+++ b/apps/web/lib/workspace-profiles.test.ts
@@ -65,8 +65,8 @@ function makeDirent(name: string, isDir: boolean): Dirent {
describe("workspace (flat workspace model)", () => {
const originalEnv = { ...process.env };
- const STATE_DIR = "/home/testuser/.openclaw-ironclaw";
- const UI_STATE_PATH = join(STATE_DIR, ".ironclaw-ui-state.json");
+ const STATE_DIR = "/home/testuser/.openclaw-dench";
+ const UI_STATE_PATH = join(STATE_DIR, ".dench-ui-state.json");
beforeEach(() => {
vi.resetModules();
@@ -147,7 +147,7 @@ describe("workspace (flat workspace model)", () => {
// ─── getEffectiveProfile ──────────────────────────────────────────
describe("getEffectiveProfile", () => {
- it("always returns 'ironclaw' regardless of env/state (single profile enforcement)", async () => {
+ it("always returns 'dench' regardless of env/state (single profile enforcement)", async () => {
process.env.OPENCLAW_PROFILE = "work";
const { getEffectiveProfile, setUIActiveProfile, mockReadFile } =
await importWorkspace();
@@ -155,7 +155,7 @@ describe("workspace (flat workspace model)", () => {
JSON.stringify({ activeWorkspace: "something" }) as never,
);
setUIActiveProfile("custom");
- expect(getEffectiveProfile()).toBe("ironclaw");
+ expect(getEffectiveProfile()).toBe("dench");
});
});
@@ -369,7 +369,7 @@ describe("workspace (flat workspace model)", () => {
expect(workspaces[0]?.isActive).toBe(true);
});
- it("keeps root default and workspace-ironclaw as distinct workspaces", async () => {
+ it("keeps root default and workspace-dench as distinct workspaces", async () => {
const { discoverWorkspaces, mockReaddir, mockExists, mockReadFile } =
await importWorkspace();
mockReadFile.mockImplementation(() => {
@@ -377,25 +377,25 @@ describe("workspace (flat workspace model)", () => {
});
mockReaddir.mockReturnValue([
makeDirent("workspace", true),
- makeDirent("workspace-ironclaw", true),
+ makeDirent("workspace-dench", true),
] as unknown as Dirent[]);
mockExists.mockImplementation((p) => {
const s = String(p);
- return s === join(STATE_DIR, "workspace") || s === join(STATE_DIR, "workspace-ironclaw");
+ return s === join(STATE_DIR, "workspace") || s === join(STATE_DIR, "workspace-dench");
});
const workspaces = discoverWorkspaces();
expect(workspaces).toHaveLength(2);
const names = workspaces.map((workspace) => workspace.name);
expect(names).toContain("default");
- expect(names).toContain("ironclaw");
+ expect(names).toContain("dench");
const rootDefault = workspaces.find((workspace) => workspace.name === "default");
- const profileIronclaw = workspaces.find((workspace) => workspace.name === "ironclaw");
+ const profileDench = workspaces.find((workspace) => workspace.name === "dench");
expect(rootDefault?.workspaceDir).toBe(join(STATE_DIR, "workspace"));
- expect(profileIronclaw?.workspaceDir).toBe(join(STATE_DIR, "workspace-ironclaw"));
+ expect(profileDench?.workspaceDir).toBe(join(STATE_DIR, "workspace-dench"));
});
- it("lists default, ironclaw, and custom workspace side by side", async () => {
+ it("lists default, dench, and custom workspace side by side", async () => {
const { discoverWorkspaces, mockReaddir, mockExists, mockReadFile } =
await importWorkspace();
mockReadFile.mockImplementation(() => {
@@ -403,14 +403,14 @@ describe("workspace (flat workspace model)", () => {
});
mockReaddir.mockReturnValue([
makeDirent("workspace", true),
- makeDirent("workspace-ironclaw", true),
+ makeDirent("workspace-dench", true),
makeDirent("workspace-kumareth", true),
] as unknown as Dirent[]);
mockExists.mockImplementation((p) => {
const s = String(p);
return (
s === join(STATE_DIR, "workspace") ||
- s === join(STATE_DIR, "workspace-ironclaw") ||
+ s === join(STATE_DIR, "workspace-dench") ||
s === join(STATE_DIR, "workspace-kumareth")
);
});
@@ -418,7 +418,7 @@ describe("workspace (flat workspace model)", () => {
const workspaces = discoverWorkspaces();
expect(workspaces.map((workspace) => workspace.name)).toEqual([
"default",
- "ironclaw",
+ "dench",
"kumareth",
]);
});
@@ -611,7 +611,7 @@ describe("workspace (flat workspace model)", () => {
mockWriteFile.mockClear();
registerWorkspacePath("myprofile", "/my/workspace");
const stateWrites = mockWriteFile.mock.calls.filter((c) =>
- (c[0] as string).includes(".ironclaw-ui-state.json"),
+ (c[0] as string).includes(".dench-ui-state.json"),
);
expect(stateWrites).toHaveLength(0);
});
diff --git a/apps/web/lib/workspace.test.ts b/apps/web/lib/workspace.test.ts
index af76fe2d609..fc2e88f0b3f 100644
--- a/apps/web/lib/workspace.test.ts
+++ b/apps/web/lib/workspace.test.ts
@@ -50,7 +50,7 @@ function makeDirent(name: string, isDir: boolean): Dirent {
describe("workspace utilities", () => {
const originalEnv = { ...process.env };
- const STATE_DIR = join("/home/testuser", ".openclaw-ironclaw");
+ const STATE_DIR = join("/home/testuser", ".openclaw-dench");
const WS_DIR = join(STATE_DIR, "workspace-test");
beforeEach(() => {
@@ -155,7 +155,7 @@ describe("workspace utilities", () => {
expect(resolveWorkspaceRoot()).toBe(fallbackWs);
});
- it("resolves bootstrap root workspace as ironclaw default", async () => {
+ it("resolves bootstrap root workspace as dench default", async () => {
delete process.env.OPENCLAW_WORKSPACE;
const { resolveWorkspaceRoot, mockExists, mockReaddir } = await importWorkspace();
const rootWorkspace = join(STATE_DIR, "workspace");
@@ -173,7 +173,7 @@ describe("workspace utilities", () => {
// ─── resolveWebChatDir ────────────────────────────────────────────
describe("resolveWebChatDir", () => {
- it("falls back to root workspace chat dir for ironclaw default", async () => {
+ it("falls back to root workspace chat dir for dench default", async () => {
delete process.env.OPENCLAW_WORKSPACE;
const { resolveWebChatDir, mockReadFile, mockReaddir } = await importWorkspace();
mockReadFile.mockImplementation(() => {
diff --git a/apps/web/lib/workspace.ts b/apps/web/lib/workspace.ts
index f0d5e1d26fd..95e8c320772 100644
--- a/apps/web/lib/workspace.ts
+++ b/apps/web/lib/workspace.ts
@@ -8,13 +8,13 @@ import { normalizeFilterGroup, type SavedView, type ViewTypeSettings } from "./o
const execAsync = promisify(exec);
-const UI_STATE_FILENAME = ".ironclaw-ui-state.json";
-const FIXED_STATE_DIRNAME = ".openclaw-ironclaw";
+const UI_STATE_FILENAME = ".dench-ui-state.json";
+const FIXED_STATE_DIRNAME = ".openclaw-dench";
const WORKSPACE_PREFIX = "workspace-";
const ROOT_WORKSPACE_DIRNAME = "workspace";
const WORKSPACE_NAME_RE = /^[a-z0-9][a-z0-9_-]{0,63}$/i;
const DEFAULT_WORKSPACE_NAME = "default";
-const IRONCLAW_PROFILE = "ironclaw";
+const DENCHCLAW_PROFILE = "dench";
/** In-memory override; takes precedence over persisted state. */
let _uiActiveWorkspace: string | null | undefined;
@@ -223,7 +223,7 @@ export function discoverProfiles(): DiscoveredProfile[] {
return discoverWorkspaces();
}
export function getEffectiveProfile(): string {
- return IRONCLAW_PROFILE;
+ return DENCHCLAW_PROFILE;
}
export function setUIActiveProfile(profile: string | null): void {
setUIActiveWorkspace(normalizeWorkspaceName(profile));
@@ -239,7 +239,7 @@ export function getRegisteredWorkspacePath(_profile: string | null): string | nu
}
export function registerWorkspacePath(_profile: string, _absolutePath: string): void {
// No-op: workspace paths are discovered from managed dirs:
- // ~/.openclaw-ironclaw/workspace (default) and ~/.openclaw-ironclaw/workspace-.
+ // ~/.openclaw-dench/workspace (default) and ~/.openclaw-dench/workspace-.
}
export function isValidWorkspaceName(name: string): boolean {
diff --git a/apps/web/package.json b/apps/web/package.json
index 90ef42075c2..cfd75afe629 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -1,5 +1,5 @@
{
- "name": "ironclaw-web",
+ "name": "denchclaw-web",
"version": "0.1.0",
"private": true,
"scripts": {
diff --git a/apps/web/vitest.config.ts b/apps/web/vitest.config.ts
index bc955623132..f121f5569ff 100644
--- a/apps/web/vitest.config.ts
+++ b/apps/web/vitest.config.ts
@@ -9,6 +9,7 @@ export default defineConfig({
resolve: {
alias: {
"@": path.resolve(__dirname),
+ "@repo": path.resolve(__dirname, "../../src"),
},
},
test: {
diff --git a/docs/install/updating.md b/docs/install/updating.md
index 8a921ec09af..497098bd788 100644
--- a/docs/install/updating.md
+++ b/docs/install/updating.md
@@ -10,7 +10,7 @@ title: "Updating"
OpenClaw is moving fast (pre “1.0”). Treat updates like shipping infra: update → run checks → restart (or use `openclaw update`, which restarts) → verify.
-If you run **IronClaw** as a frontend package, keep OpenClaw installed globally (`npm i -g openclaw`) and update OpenClaw separately; IronClaw delegates runtime commands to that global OpenClaw install.
+If you run **DenchClaw** as a frontend package, keep OpenClaw installed globally (`npm i -g openclaw`) and update OpenClaw separately; DenchClaw delegates runtime commands to that global OpenClaw install.
## Recommended: re-run the website installer (upgrade in place)
diff --git a/docs/reference/RELEASING.md b/docs/reference/RELEASING.md
index 4781f748b51..a173ed9bbd7 100644
--- a/docs/reference/RELEASING.md
+++ b/docs/reference/RELEASING.md
@@ -23,7 +23,7 @@ When the operator says “release”, immediately do this preflight (no extra qu
- [ ] Bump `package.json` version (e.g., `2026.1.29`).
- [ ] Update CLI/version strings: [`src/cli/program.ts`](https://github.com/openclaw/openclaw/blob/main/src/cli/program.ts) and the Baileys user agent in [`src/provider-web.ts`](https://github.com/openclaw/openclaw/blob/main/src/provider-web.ts).
-- [ ] Confirm package metadata (name, description, repository, keywords, license) and `bin` map points to [`openclaw.mjs`](https://github.com/openclaw/openclaw/blob/main/openclaw.mjs) for `ironclaw`.
+- [ ] Confirm package metadata (name, description, repository, keywords, license) and `bin` map points to [`openclaw.mjs`](https://github.com/openclaw/openclaw/blob/main/openclaw.mjs) for `denchclaw`.
- [ ] Confirm release notes/documentation call out the global runtime prerequisite: `npm i -g openclaw`.
- [ ] If dependencies changed, run `pnpm install` so `pnpm-lock.yaml` is current.
@@ -31,7 +31,7 @@ When the operator says “release”, immediately do this preflight (no extra qu
- [ ] If A2UI inputs changed, run `pnpm canvas:a2ui:bundle` and commit any updated [`src/canvas-host/a2ui/a2ui.bundle.js`](https://github.com/openclaw/openclaw/blob/main/src/canvas-host/a2ui/a2ui.bundle.js).
- [ ] `pnpm run build` (regenerates `dist/`).
-- [ ] Verify npm package `files` includes only IronClaw artifacts (`dist/entry*`, web standalone, skills/assets) and does not rely on bundled OpenClaw core runtime code.
+- [ ] Verify npm package `files` includes only DenchClaw artifacts (`dist/entry*`, web standalone, skills/assets) and does not rely on bundled OpenClaw core runtime code.
- [ ] Confirm `dist/build-info.json` exists and includes the expected `commit` hash (CLI banner uses this for npm installs).
- [ ] Optional: `npm pack --pack-destination /tmp` after the build; inspect the tarball contents and keep it handy for the GitHub release (do **not** commit it).
diff --git a/extensions/bluebubbles/package.json b/extensions/bluebubbles/package.json
index d345f469906..d45112b8fe3 100644
--- a/extensions/bluebubbles/package.json
+++ b/extensions/bluebubbles/package.json
@@ -4,7 +4,7 @@
"description": "OpenClaw BlueBubbles channel plugin",
"type": "module",
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"openclaw": {
"extensions": [
diff --git a/extensions/copilot-proxy/package.json b/extensions/copilot-proxy/package.json
index 9396f777cad..7d379b61189 100644
--- a/extensions/copilot-proxy/package.json
+++ b/extensions/copilot-proxy/package.json
@@ -5,7 +5,7 @@
"description": "OpenClaw Copilot Proxy provider plugin",
"type": "module",
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"openclaw": {
"extensions": [
diff --git a/extensions/denchclaw-auth/README.md b/extensions/denchclaw-auth/README.md
new file mode 100644
index 00000000000..73858c958b2
--- /dev/null
+++ b/extensions/denchclaw-auth/README.md
@@ -0,0 +1,39 @@
+# DenchClaw OAuth (OpenClaw plugin)
+
+OAuth provider plugin for DenchClaw-hosted models.
+
+## Enable
+
+Bundled plugins are disabled by default. Enable this one:
+
+```bash
+openclaw plugins enable denchclaw-auth
+```
+
+Restart the Gateway after enabling.
+
+## Authenticate
+
+Set at least a client id, then run provider login:
+
+```bash
+export DENCHCLAW_OAUTH_CLIENT_ID=""
+openclaw models auth login --provider denchclaw --set-default
+```
+
+## Optional env vars
+
+- `DENCHCLAW_OAUTH_CLIENT_SECRET`
+- `DENCHCLAW_OAUTH_AUTH_URL` (default: `https://auth.denchclaw.ai/oauth/authorize`)
+- `DENCHCLAW_OAUTH_TOKEN_URL` (default: `https://auth.denchclaw.ai/oauth/token`)
+- `DENCHCLAW_OAUTH_REDIRECT_URI` (default: `http://127.0.0.1:47089/oauth/callback`)
+- `DENCHCLAW_OAUTH_SCOPES` (space/comma separated)
+- `DENCHCLAW_OAUTH_USERINFO_URL` (optional for email display)
+- `DENCHCLAW_PROVIDER_BASE_URL` (default: `https://api.denchclaw.ai/v1`)
+- `DENCHCLAW_PROVIDER_MODEL_IDS` (space/comma separated, default: `chat`)
+- `DENCHCLAW_PROVIDER_DEFAULT_MODEL` (default: first model id)
+
+## Notes
+
+- This plugin configures `models.providers.denchclaw` as `openai-completions`.
+- OAuth tokens are stored in auth profiles and the provider is patched into config automatically.
diff --git a/extensions/ironclaw-auth/index.ts b/extensions/denchclaw-auth/index.ts
similarity index 72%
rename from extensions/ironclaw-auth/index.ts
rename to extensions/denchclaw-auth/index.ts
index d7a77230c76..ba51edd96d2 100644
--- a/extensions/ironclaw-auth/index.ts
+++ b/extensions/denchclaw-auth/index.ts
@@ -4,45 +4,45 @@ import {
type ProviderAuthContext,
type ProviderAuthResult,
} from "openclaw/plugin-sdk";
-import { loginIronclawOAuth, type IronclawOAuthConfig } from "./oauth.js";
+import { loginDenchClawOAuth, type DenchClawOAuthConfig } from "./oauth.js";
-const PLUGIN_ID = "ironclaw-auth";
-const PROVIDER_ID = "ironclaw";
-const PROVIDER_LABEL = "Ironclaw";
-const OAUTH_PLACEHOLDER = "ironclaw-oauth";
-const DEFAULT_AUTH_URL = "https://auth.ironclaw.ai/oauth/authorize";
-const DEFAULT_TOKEN_URL = "https://auth.ironclaw.ai/oauth/token";
+const PLUGIN_ID = "denchclaw-auth";
+const PROVIDER_ID = "denchclaw";
+const PROVIDER_LABEL = "DenchClaw";
+const OAUTH_PLACEHOLDER = "denchclaw-oauth";
+const DEFAULT_AUTH_URL = "https://auth.denchclaw.ai/oauth/authorize";
+const DEFAULT_TOKEN_URL = "https://auth.denchclaw.ai/oauth/token";
const DEFAULT_REDIRECT_URI = "http://127.0.0.1:47089/oauth/callback";
const DEFAULT_SCOPES = ["openid", "profile", "email", "offline_access"];
-const DEFAULT_BASE_URL = "https://api.ironclaw.ai/v1";
+const DEFAULT_BASE_URL = "https://api.denchclaw.ai/v1";
const DEFAULT_MODEL_ID = "chat";
const DEFAULT_CONTEXT_WINDOW = 128000;
const DEFAULT_MAX_TOKENS = 8192;
-const CLIENT_ID_KEYS = ["IRONCLAW_OAUTH_CLIENT_ID", "OPENCLAW_IRONCLAW_OAUTH_CLIENT_ID"];
+const CLIENT_ID_KEYS = ["DENCHCLAW_OAUTH_CLIENT_ID", "OPENCLAW_DENCHCLAW_OAUTH_CLIENT_ID"];
const CLIENT_SECRET_KEYS = [
- "IRONCLAW_OAUTH_CLIENT_SECRET",
- "OPENCLAW_IRONCLAW_OAUTH_CLIENT_SECRET",
+ "DENCHCLAW_OAUTH_CLIENT_SECRET",
+ "OPENCLAW_DENCHCLAW_OAUTH_CLIENT_SECRET",
];
-const AUTH_URL_KEYS = ["IRONCLAW_OAUTH_AUTH_URL", "OPENCLAW_IRONCLAW_OAUTH_AUTH_URL"];
-const TOKEN_URL_KEYS = ["IRONCLAW_OAUTH_TOKEN_URL", "OPENCLAW_IRONCLAW_OAUTH_TOKEN_URL"];
-const REDIRECT_URI_KEYS = ["IRONCLAW_OAUTH_REDIRECT_URI", "OPENCLAW_IRONCLAW_OAUTH_REDIRECT_URI"];
-const SCOPES_KEYS = ["IRONCLAW_OAUTH_SCOPES", "OPENCLAW_IRONCLAW_OAUTH_SCOPES"];
-const USERINFO_URL_KEYS = ["IRONCLAW_OAUTH_USERINFO_URL", "OPENCLAW_IRONCLAW_OAUTH_USERINFO_URL"];
+const AUTH_URL_KEYS = ["DENCHCLAW_OAUTH_AUTH_URL", "OPENCLAW_DENCHCLAW_OAUTH_AUTH_URL"];
+const TOKEN_URL_KEYS = ["DENCHCLAW_OAUTH_TOKEN_URL", "OPENCLAW_DENCHCLAW_OAUTH_TOKEN_URL"];
+const REDIRECT_URI_KEYS = ["DENCHCLAW_OAUTH_REDIRECT_URI", "OPENCLAW_DENCHCLAW_OAUTH_REDIRECT_URI"];
+const SCOPES_KEYS = ["DENCHCLAW_OAUTH_SCOPES", "OPENCLAW_DENCHCLAW_OAUTH_SCOPES"];
+const USERINFO_URL_KEYS = ["DENCHCLAW_OAUTH_USERINFO_URL", "OPENCLAW_DENCHCLAW_OAUTH_USERINFO_URL"];
const BASE_URL_KEYS = [
- "IRONCLAW_PROVIDER_BASE_URL",
- "IRONCLAW_API_BASE_URL",
- "OPENCLAW_IRONCLAW_PROVIDER_BASE_URL",
+ "DENCHCLAW_PROVIDER_BASE_URL",
+ "DENCHCLAW_API_BASE_URL",
+ "OPENCLAW_DENCHCLAW_PROVIDER_BASE_URL",
];
const MODEL_IDS_KEYS = [
- "IRONCLAW_PROVIDER_MODEL_IDS",
- "IRONCLAW_MODEL_IDS",
- "OPENCLAW_IRONCLAW_MODEL_IDS",
+ "DENCHCLAW_PROVIDER_MODEL_IDS",
+ "DENCHCLAW_MODEL_IDS",
+ "OPENCLAW_DENCHCLAW_MODEL_IDS",
];
const DEFAULT_MODEL_KEYS = [
- "IRONCLAW_PROVIDER_DEFAULT_MODEL",
- "IRONCLAW_DEFAULT_MODEL",
- "OPENCLAW_IRONCLAW_DEFAULT_MODEL",
+ "DENCHCLAW_PROVIDER_DEFAULT_MODEL",
+ "DENCHCLAW_DEFAULT_MODEL",
+ "OPENCLAW_DENCHCLAW_DEFAULT_MODEL",
];
const ENV_VARS = [
@@ -118,11 +118,11 @@ function buildModelDefinition(modelId: string) {
};
}
-function resolveOAuthConfig(): IronclawOAuthConfig {
+function resolveOAuthConfig(): DenchClawOAuthConfig {
const clientId = resolveEnv(CLIENT_ID_KEYS);
if (!clientId) {
throw new Error(
- ["Ironclaw OAuth client id is required.", `Set one of: ${CLIENT_ID_KEYS.join(", ")}`].join(
+ ["DenchClaw OAuth client id is required.", `Set one of: ${CLIENT_ID_KEYS.join(", ")}`].join(
"\n",
),
);
@@ -158,7 +158,7 @@ function buildAuthResult(params: {
const agentModels = Object.fromEntries(
finalModelIds.map((modelId, index) => [
`${PROVIDER_ID}/${modelId}`,
- index === 0 ? { alias: "ironclaw" } : {},
+ index === 0 ? { alias: "denchclaw" } : {},
]),
);
@@ -201,29 +201,29 @@ function buildAuthResult(params: {
};
}
-const ironclawAuthPlugin = {
+const denchclawAuthPlugin = {
id: PLUGIN_ID,
- name: "Ironclaw OAuth",
- description: "OAuth flow for Ironclaw-hosted models",
+ name: "DenchClaw OAuth",
+ description: "OAuth flow for DenchClaw-hosted models",
configSchema: emptyPluginConfigSchema(),
register(api: OpenClawPluginApi) {
api.registerProvider({
id: PROVIDER_ID,
label: PROVIDER_LABEL,
docsPath: "/providers/models",
- aliases: ["ironclaw-ai"],
+ aliases: ["denchclaw-ai"],
envVars: ENV_VARS,
auth: [
{
id: "oauth",
- label: "Ironclaw OAuth",
+ label: "DenchClaw OAuth",
hint: "PKCE + localhost callback",
kind: "oauth",
run: async (ctx: ProviderAuthContext) => {
- const progress = ctx.prompter.progress("Starting Ironclaw OAuth...");
+ const progress = ctx.prompter.progress("Starting DenchClaw OAuth...");
try {
const oauthConfig = resolveOAuthConfig();
- const result = await loginIronclawOAuth(
+ const result = await loginDenchClawOAuth(
{
isRemote: ctx.isRemote,
openUrl: ctx.openUrl,
@@ -235,16 +235,16 @@ const ironclawAuthPlugin = {
oauthConfig,
);
- progress.stop("Ironclaw OAuth complete");
+ progress.stop("DenchClaw OAuth complete");
return buildAuthResult(result);
} catch (error) {
- progress.stop("Ironclaw OAuth failed");
+ progress.stop("DenchClaw OAuth failed");
await ctx.prompter.note(
[
- "Set IRONCLAW_OAUTH_CLIENT_ID (and optionally auth/token URLs) before retrying.",
- "You can also configure model ids with IRONCLAW_PROVIDER_MODEL_IDS.",
+ "Set DENCHCLAW_OAUTH_CLIENT_ID (and optionally auth/token URLs) before retrying.",
+ "You can also configure model ids with DENCHCLAW_PROVIDER_MODEL_IDS.",
].join("\n"),
- "Ironclaw OAuth",
+ "DenchClaw OAuth",
);
throw error;
}
@@ -255,4 +255,4 @@ const ironclawAuthPlugin = {
},
};
-export default ironclawAuthPlugin;
+export default denchclawAuthPlugin;
diff --git a/extensions/ironclaw-auth/oauth.ts b/extensions/denchclaw-auth/oauth.ts
similarity index 91%
rename from extensions/ironclaw-auth/oauth.ts
rename to extensions/denchclaw-auth/oauth.ts
index ec98e815442..68a58b2cbd3 100644
--- a/extensions/ironclaw-auth/oauth.ts
+++ b/extensions/denchclaw-auth/oauth.ts
@@ -6,7 +6,7 @@ const RESPONSE_PAGE = `
- Ironclaw OAuth
+ DenchClaw OAuth
@@ -16,7 +16,7 @@ const RESPONSE_PAGE = `
`;
-export type IronclawOAuthConfig = {
+export type DenchClawOAuthConfig = {
clientId: string;
clientSecret?: string;
authUrl: string;
@@ -26,14 +26,14 @@ export type IronclawOAuthConfig = {
userInfoUrl?: string;
};
-export type IronclawOAuthCredentials = {
+export type DenchClawOAuthCredentials = {
access: string;
refresh: string;
expires: number;
email?: string;
};
-export type IronclawOAuthContext = {
+export type DenchClawOAuthContext = {
isRemote: boolean;
openUrl: (url: string) => Promise;
log: (message: string) => void;
@@ -65,11 +65,11 @@ function normalizeUrl(value: string, fieldName: string): string {
}
function buildAuthUrl(params: {
- config: IronclawOAuthConfig;
+ config: DenchClawOAuthConfig;
challenge: string;
state: string;
}): string {
- const authUrl = normalizeUrl(params.config.authUrl, "IRONCLAW_OAUTH_AUTH_URL");
+ const authUrl = normalizeUrl(params.config.authUrl, "DENCHCLAW_OAUTH_AUTH_URL");
const url = new URL(authUrl);
url.searchParams.set("client_id", params.config.clientId);
url.searchParams.set("response_type", "code");
@@ -112,7 +112,7 @@ function parseCallbackInput(
}
async function startCallbackServer(params: { redirectUri: string; timeoutMs: number }) {
- const redirect = new URL(normalizeUrl(params.redirectUri, "IRONCLAW_OAUTH_REDIRECT_URI"));
+ const redirect = new URL(normalizeUrl(params.redirectUri, "DENCHCLAW_OAUTH_REDIRECT_URI"));
const port = redirect.port ? Number(redirect.port) : 80;
const host =
redirect.hostname === "localhost" || redirect.hostname === "127.0.0.1"
@@ -189,11 +189,11 @@ async function startCallbackServer(params: { redirectUri: string; timeoutMs: num
}
async function exchangeCode(params: {
- config: IronclawOAuthConfig;
+ config: DenchClawOAuthConfig;
code: string;
verifier: string;
-}): Promise {
- const tokenUrl = normalizeUrl(params.config.tokenUrl, "IRONCLAW_OAUTH_TOKEN_URL");
+}): Promise {
+ const tokenUrl = normalizeUrl(params.config.tokenUrl, "DENCHCLAW_OAUTH_TOKEN_URL");
const body = new URLSearchParams({
grant_type: "authorization_code",
code: params.code,
@@ -240,7 +240,7 @@ async function exchangeCode(params: {
}
async function fetchUserEmail(
- config: IronclawOAuthConfig,
+ config: DenchClawOAuthConfig,
accessToken: string,
): Promise {
if (!config.userInfoUrl?.trim()) {
@@ -248,7 +248,7 @@ async function fetchUserEmail(
}
let url: string;
try {
- url = normalizeUrl(config.userInfoUrl, "IRONCLAW_OAUTH_USERINFO_URL");
+ url = normalizeUrl(config.userInfoUrl, "DENCHCLAW_OAUTH_USERINFO_URL");
} catch {
return undefined;
}
@@ -270,10 +270,10 @@ async function fetchUserEmail(
}
}
-export async function loginIronclawOAuth(
- ctx: IronclawOAuthContext,
- config: IronclawOAuthConfig,
-): Promise {
+export async function loginDenchClawOAuth(
+ ctx: DenchClawOAuthContext,
+ config: DenchClawOAuthConfig,
+): Promise {
const { verifier, challenge } = generatePkce();
const state = randomBytes(16).toString("hex");
const authUrl = buildAuthUrl({ config, challenge, state });
@@ -300,14 +300,14 @@ export async function loginIronclawOAuth(
`Auth URL: ${authUrl}`,
`Redirect URI: ${config.redirectUri}`,
].join("\n"),
- "Ironclaw OAuth",
+ "DenchClaw OAuth",
);
ctx.log("");
ctx.log("Copy this URL:");
ctx.log(authUrl);
ctx.log("");
} else {
- ctx.progress.update("Opening Ironclaw sign-in...");
+ ctx.progress.update("Opening DenchClaw sign-in...");
try {
await ctx.openUrl(authUrl);
} catch {
diff --git a/extensions/ironclaw-auth/openclaw.plugin.json b/extensions/denchclaw-auth/openclaw.plugin.json
similarity index 65%
rename from extensions/ironclaw-auth/openclaw.plugin.json
rename to extensions/denchclaw-auth/openclaw.plugin.json
index 945d9f292e4..dca5bb5095b 100644
--- a/extensions/ironclaw-auth/openclaw.plugin.json
+++ b/extensions/denchclaw-auth/openclaw.plugin.json
@@ -1,6 +1,6 @@
{
- "id": "ironclaw-auth",
- "providers": ["ironclaw"],
+ "id": "denchclaw-auth",
+ "providers": ["denchclaw"],
"configSchema": {
"type": "object",
"additionalProperties": false,
diff --git a/extensions/diagnostics-otel/package.json b/extensions/diagnostics-otel/package.json
index 0645e3f0874..8f04659a3b7 100644
--- a/extensions/diagnostics-otel/package.json
+++ b/extensions/diagnostics-otel/package.json
@@ -17,7 +17,7 @@
"@opentelemetry/semantic-conventions": "^1.39.0"
},
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"openclaw": {
"extensions": [
diff --git a/extensions/discord/package.json b/extensions/discord/package.json
index 6160d18cbfc..da912f8ba0d 100644
--- a/extensions/discord/package.json
+++ b/extensions/discord/package.json
@@ -4,7 +4,7 @@
"description": "OpenClaw Discord channel plugin",
"type": "module",
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"openclaw": {
"extensions": [
diff --git a/extensions/feishu/package.json b/extensions/feishu/package.json
index 1d7a0cb9687..7324f2f67d8 100644
--- a/extensions/feishu/package.json
+++ b/extensions/feishu/package.json
@@ -9,7 +9,7 @@
"zod": "^4.3.6"
},
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"openclaw": {
"extensions": [
diff --git a/extensions/feishu/src/dynamic-agent.ts b/extensions/feishu/src/dynamic-agent.ts
index d62c3f2a43e..52ae6880869 100644
--- a/extensions/feishu/src/dynamic-agent.ts
+++ b/extensions/feishu/src/dynamic-agent.ts
@@ -77,8 +77,9 @@ export async function maybeCreateDynamicAgent(params: {
}
// Resolve path templates with substitutions
- const workspaceTemplate = dynamicCfg.workspaceTemplate ?? "~/.openclaw/workspace-{agentId}";
- const agentDirTemplate = dynamicCfg.agentDirTemplate ?? "~/.openclaw/agents/{agentId}/agent";
+ const workspaceTemplate = dynamicCfg.workspaceTemplate ?? "~/.openclaw-dench/workspace-{agentId}";
+ const agentDirTemplate =
+ dynamicCfg.agentDirTemplate ?? "~/.openclaw-dench/agents/{agentId}/agent";
const workspace = resolveUserPath(
workspaceTemplate.replace("{userId}", senderOpenId).replace("{agentId}", agentId),
diff --git a/extensions/google-antigravity-auth/package.json b/extensions/google-antigravity-auth/package.json
index 5ba24174eef..f8679b43467 100644
--- a/extensions/google-antigravity-auth/package.json
+++ b/extensions/google-antigravity-auth/package.json
@@ -5,7 +5,7 @@
"description": "OpenClaw Google Antigravity OAuth provider plugin",
"type": "module",
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"openclaw": {
"extensions": [
diff --git a/extensions/google-gemini-cli-auth/package.json b/extensions/google-gemini-cli-auth/package.json
index 73838fa90db..28c42365c7c 100644
--- a/extensions/google-gemini-cli-auth/package.json
+++ b/extensions/google-gemini-cli-auth/package.json
@@ -5,7 +5,7 @@
"description": "OpenClaw Gemini CLI OAuth provider plugin",
"type": "module",
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"openclaw": {
"extensions": [
diff --git a/extensions/googlechat/package.json b/extensions/googlechat/package.json
index d14761dc9cd..3ee6cd99919 100644
--- a/extensions/googlechat/package.json
+++ b/extensions/googlechat/package.json
@@ -8,10 +8,10 @@
"google-auth-library": "^10.5.0"
},
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"peerDependencies": {
- "ironclaw": ">=2026.1.26"
+ "denchclaw": ">=2026.1.26"
},
"openclaw": {
"extensions": [
diff --git a/extensions/imessage/package.json b/extensions/imessage/package.json
index 8792f43baef..be5ed34bd72 100644
--- a/extensions/imessage/package.json
+++ b/extensions/imessage/package.json
@@ -5,7 +5,7 @@
"description": "OpenClaw iMessage channel plugin",
"type": "module",
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"openclaw": {
"extensions": [
diff --git a/extensions/irc/package.json b/extensions/irc/package.json
index 1b16beab476..ba70d1de13f 100644
--- a/extensions/irc/package.json
+++ b/extensions/irc/package.json
@@ -4,7 +4,7 @@
"description": "OpenClaw IRC channel plugin",
"type": "module",
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"openclaw": {
"extensions": [
diff --git a/extensions/ironclaw-auth/README.md b/extensions/ironclaw-auth/README.md
deleted file mode 100644
index 73295490277..00000000000
--- a/extensions/ironclaw-auth/README.md
+++ /dev/null
@@ -1,39 +0,0 @@
-# Ironclaw OAuth (OpenClaw plugin)
-
-OAuth provider plugin for Ironclaw-hosted models.
-
-## Enable
-
-Bundled plugins are disabled by default. Enable this one:
-
-```bash
-openclaw plugins enable ironclaw-auth
-```
-
-Restart the Gateway after enabling.
-
-## Authenticate
-
-Set at least a client id, then run provider login:
-
-```bash
-export IRONCLAW_OAUTH_CLIENT_ID=""
-openclaw models auth login --provider ironclaw --set-default
-```
-
-## Optional env vars
-
-- `IRONCLAW_OAUTH_CLIENT_SECRET`
-- `IRONCLAW_OAUTH_AUTH_URL` (default: `https://auth.ironclaw.ai/oauth/authorize`)
-- `IRONCLAW_OAUTH_TOKEN_URL` (default: `https://auth.ironclaw.ai/oauth/token`)
-- `IRONCLAW_OAUTH_REDIRECT_URI` (default: `http://127.0.0.1:47089/oauth/callback`)
-- `IRONCLAW_OAUTH_SCOPES` (space/comma separated)
-- `IRONCLAW_OAUTH_USERINFO_URL` (optional for email display)
-- `IRONCLAW_PROVIDER_BASE_URL` (default: `https://api.ironclaw.ai/v1`)
-- `IRONCLAW_PROVIDER_MODEL_IDS` (space/comma separated, default: `chat`)
-- `IRONCLAW_PROVIDER_DEFAULT_MODEL` (default: first model id)
-
-## Notes
-
-- This plugin configures `models.providers.ironclaw` as `openai-completions`.
-- OAuth tokens are stored in auth profiles and the provider is patched into config automatically.
diff --git a/extensions/line/package.json b/extensions/line/package.json
index 70dfebfcecf..3e8245c1fe8 100644
--- a/extensions/line/package.json
+++ b/extensions/line/package.json
@@ -5,7 +5,7 @@
"description": "OpenClaw LINE channel plugin",
"type": "module",
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"openclaw": {
"extensions": [
diff --git a/extensions/llm-task/package.json b/extensions/llm-task/package.json
index 816c509668f..b27cf879e15 100644
--- a/extensions/llm-task/package.json
+++ b/extensions/llm-task/package.json
@@ -5,7 +5,7 @@
"description": "OpenClaw JSON-only LLM task plugin",
"type": "module",
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"openclaw": {
"extensions": [
diff --git a/extensions/lobster/package.json b/extensions/lobster/package.json
index b6f976d566a..81cc55d8a12 100644
--- a/extensions/lobster/package.json
+++ b/extensions/lobster/package.json
@@ -4,7 +4,7 @@
"description": "Lobster workflow tool plugin (typed pipelines + resumable approvals)",
"type": "module",
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"openclaw": {
"extensions": [
diff --git a/extensions/matrix/package.json b/extensions/matrix/package.json
index 659b4a6a915..6d3e117f6ef 100644
--- a/extensions/matrix/package.json
+++ b/extensions/matrix/package.json
@@ -11,7 +11,7 @@
"zod": "^4.3.6"
},
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"openclaw": {
"extensions": [
diff --git a/extensions/mattermost/package.json b/extensions/mattermost/package.json
index 332a3e3c3c5..a46cfdb61c2 100644
--- a/extensions/mattermost/package.json
+++ b/extensions/mattermost/package.json
@@ -4,7 +4,7 @@
"description": "OpenClaw Mattermost channel plugin",
"type": "module",
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"openclaw": {
"extensions": [
diff --git a/extensions/memory-core/package.json b/extensions/memory-core/package.json
index bb879c36825..8e74e79f899 100644
--- a/extensions/memory-core/package.json
+++ b/extensions/memory-core/package.json
@@ -5,10 +5,10 @@
"description": "OpenClaw core memory search plugin",
"type": "module",
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"peerDependencies": {
- "ironclaw": ">=2026.1.26"
+ "denchclaw": ">=2026.1.26"
},
"openclaw": {
"extensions": [
diff --git a/extensions/memory-lancedb/config.ts b/extensions/memory-lancedb/config.ts
index 77d53cc6842..4a185f33481 100644
--- a/extensions/memory-lancedb/config.ts
+++ b/extensions/memory-lancedb/config.ts
@@ -23,7 +23,7 @@ const LEGACY_STATE_DIRS: string[] = [];
function resolveDefaultDbPath(): string {
const home = homedir();
- const preferred = join(home, ".openclaw", "memory", "lancedb");
+ const preferred = join(home, ".openclaw-dench", "memory", "lancedb");
try {
if (fs.existsSync(preferred)) {
return preferred;
@@ -140,7 +140,7 @@ export const memoryConfigSchema = {
},
dbPath: {
label: "Database Path",
- placeholder: "~/.openclaw/memory/lancedb",
+ placeholder: "~/.openclaw-dench/memory/lancedb",
advanced: true,
},
autoCapture: {
diff --git a/extensions/memory-lancedb/openclaw.plugin.json b/extensions/memory-lancedb/openclaw.plugin.json
index 44ee0dcd04f..2c3f5276fce 100644
--- a/extensions/memory-lancedb/openclaw.plugin.json
+++ b/extensions/memory-lancedb/openclaw.plugin.json
@@ -15,7 +15,7 @@
},
"dbPath": {
"label": "Database Path",
- "placeholder": "~/.openclaw/memory/lancedb",
+ "placeholder": "~/.openclaw-dench/memory/lancedb",
"advanced": true
},
"autoCapture": {
diff --git a/extensions/memory-lancedb/package.json b/extensions/memory-lancedb/package.json
index 971497436c7..b37910ea53b 100644
--- a/extensions/memory-lancedb/package.json
+++ b/extensions/memory-lancedb/package.json
@@ -10,7 +10,7 @@
"openai": "^6.22.0"
},
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"openclaw": {
"extensions": [
diff --git a/extensions/minimax-portal-auth/package.json b/extensions/minimax-portal-auth/package.json
index 7805572dede..8755e5b35b7 100644
--- a/extensions/minimax-portal-auth/package.json
+++ b/extensions/minimax-portal-auth/package.json
@@ -5,7 +5,7 @@
"description": "OpenClaw MiniMax Portal OAuth provider plugin",
"type": "module",
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"openclaw": {
"extensions": [
diff --git a/extensions/msteams/package.json b/extensions/msteams/package.json
index c4d14838c10..e63bb9a58ff 100644
--- a/extensions/msteams/package.json
+++ b/extensions/msteams/package.json
@@ -8,7 +8,7 @@
"express": "^5.2.1"
},
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"openclaw": {
"extensions": [
diff --git a/extensions/nextcloud-talk/package.json b/extensions/nextcloud-talk/package.json
index 1eac3761763..f46455079e9 100644
--- a/extensions/nextcloud-talk/package.json
+++ b/extensions/nextcloud-talk/package.json
@@ -4,7 +4,7 @@
"description": "OpenClaw Nextcloud Talk channel plugin",
"type": "module",
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"openclaw": {
"extensions": [
diff --git a/extensions/nostr/package.json b/extensions/nostr/package.json
index 59912d9ce2d..76113c69da8 100644
--- a/extensions/nostr/package.json
+++ b/extensions/nostr/package.json
@@ -8,7 +8,7 @@
"zod": "^4.3.6"
},
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"openclaw": {
"extensions": [
diff --git a/extensions/open-prose/package.json b/extensions/open-prose/package.json
index e82029d2896..afcda92b40f 100644
--- a/extensions/open-prose/package.json
+++ b/extensions/open-prose/package.json
@@ -5,7 +5,7 @@
"description": "OpenProse VM skill pack plugin (slash command + telemetry).",
"type": "module",
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"openclaw": {
"extensions": [
diff --git a/extensions/signal/package.json b/extensions/signal/package.json
index 972effc8904..538f3ad31df 100644
--- a/extensions/signal/package.json
+++ b/extensions/signal/package.json
@@ -5,7 +5,7 @@
"description": "OpenClaw Signal channel plugin",
"type": "module",
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"openclaw": {
"extensions": [
diff --git a/extensions/slack/package.json b/extensions/slack/package.json
index bc5c880225c..2b41279b457 100644
--- a/extensions/slack/package.json
+++ b/extensions/slack/package.json
@@ -5,7 +5,7 @@
"description": "OpenClaw Slack channel plugin",
"type": "module",
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"openclaw": {
"extensions": [
diff --git a/extensions/synology-chat/package.json b/extensions/synology-chat/package.json
index 14be854f2ad..96530358294 100644
--- a/extensions/synology-chat/package.json
+++ b/extensions/synology-chat/package.json
@@ -5,7 +5,7 @@
"description": "Synology Chat channel plugin for OpenClaw",
"type": "module",
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"openclaw": {
"extensions": [
diff --git a/extensions/telegram/package.json b/extensions/telegram/package.json
index 417b2c68ab5..ac7e163b43a 100644
--- a/extensions/telegram/package.json
+++ b/extensions/telegram/package.json
@@ -5,7 +5,7 @@
"description": "OpenClaw Telegram channel plugin",
"type": "module",
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"openclaw": {
"extensions": [
diff --git a/extensions/tlon/package.json b/extensions/tlon/package.json
index 6c6435e4b92..2459727a91c 100644
--- a/extensions/tlon/package.json
+++ b/extensions/tlon/package.json
@@ -7,7 +7,7 @@
"@urbit/aura": "^3.0.0"
},
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"openclaw": {
"extensions": [
diff --git a/extensions/twitch/package.json b/extensions/twitch/package.json
index 6ec941fadd3..5efc107708e 100644
--- a/extensions/twitch/package.json
+++ b/extensions/twitch/package.json
@@ -10,7 +10,7 @@
"zod": "^4.3.6"
},
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"openclaw": {
"extensions": [
diff --git a/extensions/voice-call/package.json b/extensions/voice-call/package.json
index bac64caa226..e980d8a4042 100644
--- a/extensions/voice-call/package.json
+++ b/extensions/voice-call/package.json
@@ -9,7 +9,7 @@
"zod": "^4.3.6"
},
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"openclaw": {
"extensions": [
diff --git a/extensions/voice-call/src/cli.ts b/extensions/voice-call/src/cli.ts
index eaf4e3fc0a5..59cbea6ba43 100644
--- a/extensions/voice-call/src/cli.ts
+++ b/extensions/voice-call/src/cli.ts
@@ -27,7 +27,7 @@ function resolveMode(input: string): "off" | "serve" | "funnel" {
}
function resolveDefaultStorePath(config: VoiceCallConfig): string {
- const preferred = path.join(os.homedir(), ".openclaw", "voice-calls");
+ const preferred = path.join(os.homedir(), ".openclaw-dench", "voice-calls");
const resolvedPreferred = resolveUserPath(preferred);
const existing =
[resolvedPreferred].find((dir) => {
diff --git a/extensions/voice-call/src/core-bridge.ts b/extensions/voice-call/src/core-bridge.ts
index e2daf5401ee..b06049833c6 100644
--- a/extensions/voice-call/src/core-bridge.ts
+++ b/extensions/voice-call/src/core-bridge.ts
@@ -109,7 +109,7 @@ function resolveOpenClawRoot(): string {
}
for (const start of candidates) {
- for (const name of ["ironclaw", "openclaw"]) {
+ for (const name of ["denchclaw", "openclaw"]) {
const found = findPackageRoot(start, name);
if (found) {
coreRootCache = found;
diff --git a/extensions/voice-call/src/manager.ts b/extensions/voice-call/src/manager.ts
index 927899f325c..cd89329bb82 100644
--- a/extensions/voice-call/src/manager.ts
+++ b/extensions/voice-call/src/manager.ts
@@ -22,7 +22,7 @@ function resolveDefaultStoreBase(config: VoiceCallConfig, storePath?: string): s
if (rawOverride) {
return resolveUserPath(rawOverride);
}
- const preferred = path.join(os.homedir(), ".openclaw", "voice-calls");
+ const preferred = path.join(os.homedir(), ".openclaw-dench", "voice-calls");
const candidates = [preferred].map((dir) => resolveUserPath(dir));
const existing =
candidates.find((dir) => {
diff --git a/extensions/whatsapp/package.json b/extensions/whatsapp/package.json
index 07b9884edd7..e81ad07ba71 100644
--- a/extensions/whatsapp/package.json
+++ b/extensions/whatsapp/package.json
@@ -5,7 +5,7 @@
"description": "OpenClaw WhatsApp channel plugin",
"type": "module",
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"openclaw": {
"extensions": [
diff --git a/extensions/zalo/package.json b/extensions/zalo/package.json
index 1d14a0a0137..78454b02242 100644
--- a/extensions/zalo/package.json
+++ b/extensions/zalo/package.json
@@ -7,7 +7,7 @@
"undici": "7.22.0"
},
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"openclaw": {
"extensions": [
diff --git a/extensions/zalouser/package.json b/extensions/zalouser/package.json
index e5dca61c93a..800a656bdd4 100644
--- a/extensions/zalouser/package.json
+++ b/extensions/zalouser/package.json
@@ -7,7 +7,7 @@
"@sinclair/typebox": "0.34.48"
},
"devDependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
},
"openclaw": {
"extensions": [
diff --git a/openclaw.mjs b/openclaw.mjs
index 44ba0cc6466..5b5535d9902 100755
--- a/openclaw.mjs
+++ b/openclaw.mjs
@@ -52,5 +52,5 @@ if (await tryImport("./dist/entry.js")) {
} else if (await tryImport("./dist/entry.mjs")) {
// OK
} else {
- throw new Error("ironclaw: missing dist/entry.(m)js (build output).");
+ throw new Error("denchclaw: missing dist/entry.(m)js (build output).");
}
diff --git a/package.json b/package.json
index 462805e3c73..d8241fe9811 100644
--- a/package.json
+++ b/package.json
@@ -1,5 +1,5 @@
{
- "name": "ironclaw",
+ "name": "denchclaw",
"version": "2026.2.22-1.1",
"description": "AI-powered CRM platform with multi-channel agent gateway, DuckDB workspace, and knowledge management",
"keywords": [],
@@ -14,7 +14,8 @@
"url": "git+https://github.com/openclaw/openclaw.git"
},
"bin": {
- "ironclaw": "openclaw.mjs"
+ "dench": "openclaw.mjs",
+ "denchclaw": "openclaw.mjs"
},
"directories": {
"doc": "docs",
@@ -57,6 +58,8 @@
"deadcode:report:ci:ts-unused": "mkdir -p .artifacts/deadcode && pnpm deadcode:ts-unused > .artifacts/deadcode/ts-unused-exports.txt 2>&1 || true",
"deadcode:ts-prune": "pnpm dlx ts-prune src extensions scripts",
"deadcode:ts-unused": "pnpm dlx ts-unused-exports tsconfig.json --ignoreTestFiles --exitWithCount",
+ "denchclaw": "node scripts/run-node.mjs",
+ "denchclaw:rpc": "node scripts/run-node.mjs agent --mode rpc --json",
"dev": "node scripts/run-node.mjs",
"docs:bin": "node scripts/build-docs-list.mjs",
"docs:check-links": "node scripts/docs-link-audit.mjs",
@@ -79,8 +82,6 @@
"ios:gen": "bash -lc './scripts/ios-configure-signing.sh && cd apps/ios && xcodegen generate'",
"ios:open": "bash -lc './scripts/ios-configure-signing.sh && cd apps/ios && xcodegen generate && open OpenClaw.xcodeproj'",
"ios:run": "bash -lc './scripts/ios-configure-signing.sh && cd apps/ios && xcodegen generate && xcodebuild -project OpenClaw.xcodeproj -scheme OpenClaw -destination \"${IOS_DEST:-platform=iOS Simulator,name=iPhone 17}\" -configuration Debug build && xcrun simctl boot \"${IOS_SIM:-iPhone 17}\" || true && xcrun simctl launch booted ai.openclaw.ios'",
- "ironclaw": "node scripts/run-node.mjs",
- "ironclaw:rpc": "node scripts/run-node.mjs agent --mode rpc --json",
"lint": "oxlint --type-aware",
"lint:all": "pnpm lint && pnpm lint:swift",
"lint:docs": "pnpm dlx markdownlint-cli2",
diff --git a/packages/clawdbot/package.json b/packages/clawdbot/package.json
index 8a66757ba50..8e095e963c9 100644
--- a/packages/clawdbot/package.json
+++ b/packages/clawdbot/package.json
@@ -11,6 +11,6 @@
"./cli-entry": "./bin/clawdbot.js"
},
"dependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
}
}
diff --git a/packages/moltbot/package.json b/packages/moltbot/package.json
index 45bd2e8cec8..12fc0f61c8a 100644
--- a/packages/moltbot/package.json
+++ b/packages/moltbot/package.json
@@ -11,6 +11,6 @@
"./cli-entry": "./bin/moltbot.js"
},
"dependencies": {
- "ironclaw": "workspace:*"
+ "denchclaw": "workspace:*"
}
}
diff --git a/scripts/deploy.sh b/scripts/deploy.sh
index f7321a3c890..bf807b87ce1 100755
--- a/scripts/deploy.sh
+++ b/scripts/deploy.sh
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
-# deploy.sh — build and publish ironclaw to npm
+# deploy.sh — build and publish denchclaw to npm
#
# Versioning convention (mirrors upstream openclaw tags):
# --upstream Sync to an upstream release version.
@@ -19,7 +19,7 @@
set -euo pipefail
-PACKAGE_NAME="ironclaw"
+PACKAGE_NAME="denchclaw"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
@@ -188,7 +188,7 @@ fi
# ── build ────────────────────────────────────────────────────────────────────
-# The `prepack` script (triggered by `npm publish`) runs the IronClaw build chain:
+# The `prepack` script (triggered by `npm publish`) runs the DenchClaw build chain:
# pnpm build && pnpm web:build && pnpm web:prepack
# Running `pnpm build` here is a redundant fail-fast: catch CLI build errors
# before committing to a publish attempt.
@@ -203,7 +203,7 @@ fi
# ── publish ──────────────────────────────────────────────────────────────────
# Always tag as "latest" — npm skips the latest tag for prerelease versions
-# by default, but we want `npm i -g ironclaw` to always resolve to
+# by default, but we want `npm i -g denchclaw` to always resolve to
# the most recently published version.
echo "publishing ${PACKAGE_NAME}@${VERSION}..."
npm publish --access public --tag latest "${NPM_FLAGS[@]}"
diff --git a/src/cli/TESTING_EDGE_CASE_MATRIX.md b/src/cli/TESTING_EDGE_CASE_MATRIX.md
index d37974dfd20..08b2ad99f7e 100644
--- a/src/cli/TESTING_EDGE_CASE_MATRIX.md
+++ b/src/cli/TESTING_EDGE_CASE_MATRIX.md
@@ -14,32 +14,32 @@ argument/env handling are treated as contract.
## Edge Matrix
-| Module | Edge Case | Invariant Protected | Test File |
-| ----------------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
-| `argv.ts` | `--` terminator handling | Flags after terminator are ignored for root parsing decisions | `src/cli/argv.test.ts` (new) |
-| `argv.ts` | `--profile` missing/empty/equals forms | Missing value returns `null`/`undefined` exactly as designed; invalid values are not coerced | `src/cli/argv.test.ts` (new) |
-| `argv.ts` | Positive int flag parsing (`0`, negative, NaN) | Invalid positive-int values are rejected without accidental fallback | `src/cli/argv.test.ts` (new) |
-| `argv.ts` | Root `-v` alias vs command path | Root version alias is honored only in root-flag contexts, never when a command path is present | `src/cli/argv.test.ts` (new) |
-| `argv.ts` | `buildParseArgv` runtime forms (`node`, `node-XX`, `bun`, direct binary) | Parse argv bootstrap is stable across runtimes and executable names | `src/cli/argv.test.ts` (new) |
-| `argv.ts` | `shouldMigrateState` exemptions | Read-only/status commands never trigger migration path | `src/cli/argv.test.ts` (new) |
-| `run-main.ts` | bootstrap cutover rollout stages | `legacy` always disables cutover, `beta` requires explicit opt-in, `default/internal` enable by default | `src/cli/run-main.test.ts` (existing, expand) |
-| `run-main.ts` | delegation disabled flags | Delegation is off when disable env is truthy in either namespace | `src/cli/run-main.test.ts` (existing, expand) |
-| `run-main.ts` | delegation loop prevention | Delegation loop env markers hard-stop with explicit error | `src/cli/run-main.test.ts` (existing, expand) |
-| `run-main.ts` | `shouldEnsureCliPath` command carve-outs | Health/status/read-only commands skip path mutations | `src/cli/run-main.test.ts` (existing, expand) |
-| `profile-utils.ts` | profile name normalization | Only valid profile names are accepted; normalization is idempotent | `src/cli/profile-utils.test.ts` (new) |
-| `profile.ts` | `--dev` + `--profile` conflict | Conflict is rejected with non-zero outcome and actionable error text | `src/cli/profile.test.ts` (new) |
-| `profile.ts` | explicit profile propagation | Parsed profile and env output are stable regardless of option ordering | `src/cli/profile.test.ts` (new) |
-| `profile.ts` | root vs command-local bootstrap profile flag | `ironclaw --profile X bootstrap` and `ironclaw bootstrap --profile X` resolve to identical profile env | `src/cli/profile.test.ts` (existing, expand) |
-| `windows-argv.ts` | control chars and duplicate exec path | Normalization removes terminal control noise while preserving args | `src/cli/windows-argv.test.ts` (new) |
-| `windows-argv.ts` | quoted executable path stripping | Windows executable wrappers are normalized without dropping real args | `src/cli/windows-argv.test.ts` (new) |
-| `respawn-policy.ts` | help/version short-circuit | Help/version always bypass respawn behavior | `src/cli/respawn-policy.test.ts` (new) |
-| `cli-name.ts` | cli name resolution/replacement | Name replacement only targets intended CLI token boundaries | `src/cli/cli-name.test.ts` (new) |
-| `ports.ts` | malformed `lsof` lines | Port parser tolerates malformed rows and only returns valid process records | `src/cli/ports.test.ts` (new) |
-| `cli-utils.ts` | runtime command failure path | Command failures return deterministic non-zero exit behavior | `src/cli/cli-utils.test.ts` (new) |
-| `bootstrap-external.ts` | auth profile mismatch/missing | Missing or mismatched provider auth fails with remediation | `src/cli/bootstrap-external.test.ts` (existing) |
-| `bootstrap-external.ts` | onboarding/gateway auto-fix workflow | Bootstrap command executes expected fallback sequence and reports recovery outcome | `src/cli/bootstrap-external.bootstrap-command.test.ts` (existing) |
-| `bootstrap-external.ts` | device signature/token mismatch remediation | Device-auth failures provide reset-first guidance + break-glass toggle with explicit revert | `src/cli/bootstrap-external.test.ts` (existing, expand) |
-| `bootstrap-external.ts` | web UI port ownership and deterministic bootstrap port selection | Bootstrap never silently drifts to sibling web ports and keeps expected UI URL stable | `src/cli/bootstrap-external.bootstrap-command.test.ts` (expand) |
+| Module | Edge Case | Invariant Protected | Test File |
+| ----------------------- | ------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
+| `argv.ts` | `--` terminator handling | Flags after terminator are ignored for root parsing decisions | `src/cli/argv.test.ts` (new) |
+| `argv.ts` | `--profile` missing/empty/equals forms | Missing value returns `null`/`undefined` exactly as designed; invalid values are not coerced | `src/cli/argv.test.ts` (new) |
+| `argv.ts` | Positive int flag parsing (`0`, negative, NaN) | Invalid positive-int values are rejected without accidental fallback | `src/cli/argv.test.ts` (new) |
+| `argv.ts` | Root `-v` alias vs command path | Root version alias is honored only in root-flag contexts, never when a command path is present | `src/cli/argv.test.ts` (new) |
+| `argv.ts` | `buildParseArgv` runtime forms (`node`, `node-XX`, `bun`, direct binary) | Parse argv bootstrap is stable across runtimes and executable names | `src/cli/argv.test.ts` (new) |
+| `argv.ts` | `shouldMigrateState` exemptions | Read-only/status commands never trigger migration path | `src/cli/argv.test.ts` (new) |
+| `run-main.ts` | bootstrap cutover rollout stages | `legacy` always disables cutover, `beta` requires explicit opt-in, `default/internal` enable by default | `src/cli/run-main.test.ts` (existing, expand) |
+| `run-main.ts` | delegation disabled flags | Delegation is off when disable env is truthy in either namespace | `src/cli/run-main.test.ts` (existing, expand) |
+| `run-main.ts` | delegation loop prevention | Delegation loop env markers hard-stop with explicit error | `src/cli/run-main.test.ts` (existing, expand) |
+| `run-main.ts` | `shouldEnsureCliPath` command carve-outs | Health/status/read-only commands skip path mutations | `src/cli/run-main.test.ts` (existing, expand) |
+| `profile-utils.ts` | profile name normalization | Only valid profile names are accepted; normalization is idempotent | `src/cli/profile-utils.test.ts` (new) |
+| `profile.ts` | `--dev` + `--profile` conflict | Conflict is rejected with non-zero outcome and actionable error text | `src/cli/profile.test.ts` (new) |
+| `profile.ts` | explicit profile propagation | Parsed profile and env output are stable regardless of option ordering | `src/cli/profile.test.ts` (new) |
+| `profile.ts` | root vs command-local bootstrap profile flag | `denchclaw --profile X bootstrap` and `denchclaw bootstrap --profile X` resolve to identical profile env | `src/cli/profile.test.ts` (existing, expand) |
+| `windows-argv.ts` | control chars and duplicate exec path | Normalization removes terminal control noise while preserving args | `src/cli/windows-argv.test.ts` (new) |
+| `windows-argv.ts` | quoted executable path stripping | Windows executable wrappers are normalized without dropping real args | `src/cli/windows-argv.test.ts` (new) |
+| `respawn-policy.ts` | help/version short-circuit | Help/version always bypass respawn behavior | `src/cli/respawn-policy.test.ts` (new) |
+| `cli-name.ts` | cli name resolution/replacement | Name replacement only targets intended CLI token boundaries | `src/cli/cli-name.test.ts` (new) |
+| `ports.ts` | malformed `lsof` lines | Port parser tolerates malformed rows and only returns valid process records | `src/cli/ports.test.ts` (new) |
+| `cli-utils.ts` | runtime command failure path | Command failures return deterministic non-zero exit behavior | `src/cli/cli-utils.test.ts` (new) |
+| `bootstrap-external.ts` | auth profile mismatch/missing | Missing or mismatched provider auth fails with remediation | `src/cli/bootstrap-external.test.ts` (existing) |
+| `bootstrap-external.ts` | onboarding/gateway auto-fix workflow | Bootstrap command executes expected fallback sequence and reports recovery outcome | `src/cli/bootstrap-external.bootstrap-command.test.ts` (existing) |
+| `bootstrap-external.ts` | device signature/token mismatch remediation | Device-auth failures provide reset-first guidance + break-glass toggle with explicit revert | `src/cli/bootstrap-external.test.ts` (existing, expand) |
+| `bootstrap-external.ts` | web UI port ownership and deterministic bootstrap port selection | Bootstrap never silently drifts to sibling web ports and keeps expected UI URL stable | `src/cli/bootstrap-external.bootstrap-command.test.ts` (expand) |
## Exit/Output Contract Checks
diff --git a/src/cli/argv.test.ts b/src/cli/argv.test.ts
index 88051ebbee2..2bcfc08277e 100644
--- a/src/cli/argv.test.ts
+++ b/src/cli/argv.test.ts
@@ -13,64 +13,66 @@ import {
describe("argv helpers", () => {
it("detects help/version flags and root -v alias only in root-flag contexts", () => {
- expect(hasHelpOrVersion(["node", "ironclaw", "--help"])).toBe(true);
- expect(hasHelpOrVersion(["node", "ironclaw", "-V"])).toBe(true);
- expect(hasHelpOrVersion(["node", "ironclaw", "-v"])).toBe(true);
- expect(hasRootVersionAlias(["node", "ironclaw", "-v", "chat"])).toBe(false);
+ expect(hasHelpOrVersion(["node", "denchclaw", "--help"])).toBe(true);
+ expect(hasHelpOrVersion(["node", "denchclaw", "-V"])).toBe(true);
+ expect(hasHelpOrVersion(["node", "denchclaw", "-v"])).toBe(true);
+ expect(hasRootVersionAlias(["node", "denchclaw", "-v", "chat"])).toBe(false);
});
it("extracts flag values across --name value and --name=value forms", () => {
- expect(getFlagValue(["node", "ironclaw", "--profile", "dev"], "--profile")).toBe("dev");
- expect(getFlagValue(["node", "ironclaw", "--profile=team-a"], "--profile")).toBe("team-a");
- expect(getFlagValue(["node", "ironclaw", "--profile", "--verbose"], "--profile")).toBeNull();
- expect(getFlagValue(["node", "ironclaw", "--profile="], "--profile")).toBeNull();
+ expect(getFlagValue(["node", "denchclaw", "--profile", "dev"], "--profile")).toBe("dev");
+ expect(getFlagValue(["node", "denchclaw", "--profile=team-a"], "--profile")).toBe("team-a");
+ expect(getFlagValue(["node", "denchclaw", "--profile", "--verbose"], "--profile")).toBeNull();
+ expect(getFlagValue(["node", "denchclaw", "--profile="], "--profile")).toBeNull();
});
it("parses positive integer flags and rejects invalid numeric values", () => {
- expect(getPositiveIntFlagValue(["node", "ironclaw", "--port", "19001"], "--port")).toBe(19001);
- expect(getPositiveIntFlagValue(["node", "ironclaw", "--port", "0"], "--port")).toBeUndefined();
- expect(getPositiveIntFlagValue(["node", "ironclaw", "--port", "-1"], "--port")).toBeUndefined();
+ expect(getPositiveIntFlagValue(["node", "denchclaw", "--port", "19001"], "--port")).toBe(19001);
+ expect(getPositiveIntFlagValue(["node", "denchclaw", "--port", "0"], "--port")).toBeUndefined();
expect(
- getPositiveIntFlagValue(["node", "ironclaw", "--port", "abc"], "--port"),
+ getPositiveIntFlagValue(["node", "denchclaw", "--port", "-1"], "--port"),
+ ).toBeUndefined();
+ expect(
+ getPositiveIntFlagValue(["node", "denchclaw", "--port", "abc"], "--port"),
).toBeUndefined();
});
it("derives command path while skipping leading flags and stopping at terminator", () => {
// Low-level parser skips flag tokens but not their values.
- expect(getCommandPath(["node", "ironclaw", "--profile", "dev", "chat"], 2)).toEqual([
+ expect(getCommandPath(["node", "denchclaw", "--profile", "dev", "chat"], 2)).toEqual([
"dev",
"chat",
]);
- expect(getCommandPath(["node", "ironclaw", "config", "get"], 2)).toEqual(["config", "get"]);
- expect(getCommandPath(["node", "ironclaw", "--", "chat", "send"], 2)).toEqual([]);
- expect(getPrimaryCommand(["node", "ironclaw", "--verbose", "status"])).toBe("status");
+ expect(getCommandPath(["node", "denchclaw", "config", "get"], 2)).toEqual(["config", "get"]);
+ expect(getCommandPath(["node", "denchclaw", "--", "chat", "send"], 2)).toEqual([]);
+ expect(getPrimaryCommand(["node", "denchclaw", "--verbose", "status"])).toBe("status");
});
it("builds parse argv consistently across runtime invocation styles", () => {
expect(
buildParseArgv({
- programName: "ironclaw",
+ programName: "denchclaw",
rawArgs: ["node", "cli.js", "status"],
}),
).toEqual(["node", "cli.js", "status"]);
expect(
buildParseArgv({
- programName: "ironclaw",
- rawArgs: ["ironclaw", "status"],
+ programName: "denchclaw",
+ rawArgs: ["denchclaw", "status"],
}),
- ).toEqual(["node", "ironclaw", "status"]);
+ ).toEqual(["node", "denchclaw", "status"]);
expect(
buildParseArgv({
- programName: "ironclaw",
+ programName: "denchclaw",
rawArgs: ["node-22.12.0.exe", "cli.js", "agent", "run"],
}),
).toEqual(["node-22.12.0.exe", "cli.js", "agent", "run"]);
expect(
buildParseArgv({
- programName: "ironclaw",
+ programName: "denchclaw",
rawArgs: ["bun", "cli.ts", "status"],
}),
).toEqual(["bun", "cli.ts", "status"]);
@@ -87,7 +89,7 @@ describe("argv helpers", () => {
expect(shouldMigrateStateFromPath(["agent"])).toBe(false);
expect(shouldMigrateStateFromPath(["chat", "send"])).toBe(true);
- expect(shouldMigrateState(["node", "ironclaw", "health"])).toBe(false);
- expect(shouldMigrateState(["node", "ironclaw", "chat", "send"])).toBe(true);
+ expect(shouldMigrateState(["node", "denchclaw", "health"])).toBe(false);
+ expect(shouldMigrateState(["node", "denchclaw", "chat", "send"])).toBe(true);
});
});
diff --git a/src/cli/argv.ts b/src/cli/argv.ts
index 0274690f105..091d396df15 100644
--- a/src/cli/argv.ts
+++ b/src/cli/argv.ts
@@ -160,7 +160,7 @@ export function buildParseArgv(params: {
const normalizedArgv =
programName && baseArgv[0] === programName
? baseArgv.slice(1)
- : baseArgv[0]?.endsWith("openclaw") || baseArgv[0]?.endsWith("ironclaw")
+ : baseArgv[0]?.endsWith("openclaw") || baseArgv[0]?.endsWith("denchclaw")
? baseArgv.slice(1)
: baseArgv;
const executable = (normalizedArgv[0]?.split(/[/\\]/).pop() ?? "").toLowerCase();
@@ -169,7 +169,7 @@ export function buildParseArgv(params: {
if (looksLikeNode) {
return normalizedArgv;
}
- return ["node", programName || "ironclaw", ...normalizedArgv];
+ return ["node", programName || "denchclaw", ...normalizedArgv];
}
const nodeExecutablePattern = /^node-\d+(?:\.\d+)*(?:\.exe)?$/;
diff --git a/src/cli/banner.ts b/src/cli/banner.ts
index b6c0fcc533e..5450355f9d7 100644
--- a/src/cli/banner.ts
+++ b/src/cli/banner.ts
@@ -21,15 +21,15 @@ const hasVersionFlag = (argv: string[]) =>
argv.some((arg) => arg === "--version" || arg === "-V") || hasRootVersionAlias(argv);
// ---------------------------------------------------------------------------
-// IRONCLAW ASCII art (figlet "ANSI Shadow" font, baked at build time)
+// DENCHCLAW ASCII art (figlet "ANSI Shadow" font, baked at build time)
// ---------------------------------------------------------------------------
-const IRONCLAW_ASCII = [
- " ██╗██████╗ ██████╗ ███╗ ██╗ ██████╗██╗ █████╗ ██╗ ██╗",
- " ██║██╔══██╗██╔═══██╗████╗ ██║██╔════╝██║ ██╔══██╗██║ ██║",
- " ██║██████╔╝██║ ██║██╔██╗ ██║██║ ██║ ███████║██║ █╗ ██║",
- " ██║██╔══██╗██║ ██║██║╚██╗██║██║ ██║ ██╔══██║██║███╗██║",
- " ██║██║ ██║╚██████╔╝██║ ╚████║╚██████╗███████╗██║ ██║╚███╔███╔╝",
- " ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝╚══════╝╚═╝ ╚═╝ ╚══╝╚══╝ ",
+const DENCHCLAW_ASCII = [
+ "██████╗ ███████╗███╗ ██╗ ██████╗██╗ ██╗ ██████╗██╗ █████╗ ██╗ ██╗",
+ "██╔══██╗██╔════╝████╗ ██║██╔════╝██║ ██║██╔════╝██║ ██╔══██╗██║ ██║",
+ "██║ ██║█████╗ ██╔██╗ ██║██║ ███████║██║ ██║ ███████║██║ █╗ ██║",
+ "██║ ██║██╔══╝ ██║╚██╗██║██║ ██╔══██║██║ ██║ ██╔══██║██║███╗██║",
+ "██████╔╝███████╗██║ ╚████║╚██████╗██║ ██║╚██████╗███████╗██║ ██║╚███╔███╔╝",
+ "╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═════╝╚═╝ ╚═╝ ╚═════╝╚══════╝╚═╝ ╚═╝ ╚══╝╚══╝ ",
];
// ---------------------------------------------------------------------------
@@ -71,19 +71,19 @@ const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve,
* at 12 fps, completing 3 full gradient cycles.
*/
async function animateIronBanner(): Promise {
- const lineCount = IRONCLAW_ASCII.length;
+ const lineCount = DENCHCLAW_ASCII.length;
const fps = 12;
const totalFrames = IRON_GRADIENT_COLORS.length * 3; // 3 full shimmer sweeps
const frameMs = Math.round(1000 / fps);
// Print the first frame to claim vertical space
- process.stdout.write(renderGradientFrame(IRONCLAW_ASCII, 0) + "\n");
+ process.stdout.write(renderGradientFrame(DENCHCLAW_ASCII, 0) + "\n");
for (let frame = 1; frame < totalFrames; frame++) {
await sleep(frameMs);
// Move cursor up to overwrite the previous frame
process.stdout.write(`\x1b[${lineCount}A\r`);
- process.stdout.write(renderGradientFrame(IRONCLAW_ASCII, frame) + "\n");
+ process.stdout.write(renderGradientFrame(DENCHCLAW_ASCII, frame) + "\n");
}
}
@@ -94,9 +94,9 @@ async function animateIronBanner(): Promise {
export function formatCliBannerArt(options: BannerOptions = {}): string {
const rich = options.richTty ?? isRich();
if (!rich) {
- return IRONCLAW_ASCII.join("\n");
+ return DENCHCLAW_ASCII.join("\n");
}
- return renderGradientFrame(IRONCLAW_ASCII, 0);
+ return renderGradientFrame(DENCHCLAW_ASCII, 0);
}
// ---------------------------------------------------------------------------
@@ -108,7 +108,7 @@ export function formatCliBannerLine(version: string, options: BannerOptions = {}
const commitLabel = commit ?? "unknown";
const tagline = pickTagline(options);
const rich = options.richTty ?? isRich();
- const title = "IRONCLAW";
+ const title = "DENCHCLAW";
const prefix = " ";
const columns = options.columns ?? process.stdout.columns ?? 120;
const plainFullLine = `${prefix}${title} ${version} (${commitLabel}) — ${tagline}`;
@@ -162,7 +162,7 @@ export async function emitCliBanner(version: string, options: BannerOptions = {}
await animateIronBanner();
} else {
// Plain ASCII fallback
- process.stdout.write(IRONCLAW_ASCII.join("\n") + "\n");
+ process.stdout.write(DENCHCLAW_ASCII.join("\n") + "\n");
}
const line = formatCliBannerLine(version, options);
diff --git a/src/cli/bootstrap-external.test.ts b/src/cli/bootstrap-external.test.ts
index 157e294ba58..e11d44a32df 100644
--- a/src/cli/bootstrap-external.test.ts
+++ b/src/cli/bootstrap-external.test.ts
@@ -20,12 +20,13 @@ function getCheck(
}
function createTempStateDir(): string {
- const dir = path.join(
+ const homeDir = path.join(
tmpdir(),
- `ironclaw-test-${Date.now()}-${Math.random().toString(36).slice(2)}`,
+ `denchclaw-test-${Date.now()}-${Math.random().toString(36).slice(2)}`,
);
- mkdirSync(dir, { recursive: true });
- return dir;
+ const stateDir = path.join(homeDir, ".openclaw-dench");
+ mkdirSync(stateDir, { recursive: true });
+ return stateDir;
}
function writeConfig(stateDir: string, config: Record): void {
@@ -63,7 +64,7 @@ describe("bootstrap-external diagnostics", () => {
});
const baseParams = (dir: string) => ({
- profile: "ironclaw",
+ profile: "dench",
openClawCliAvailable: true,
openClawVersion: "2026.3.1",
gatewayPort: 18789,
@@ -74,7 +75,7 @@ describe("bootstrap-external diagnostics", () => {
rolloutStage: "default" as const,
legacyFallbackEnabled: false,
stateDir: dir,
- env: { HOME: "/home/testuser" },
+ env: { HOME: path.dirname(dir), OPENCLAW_HOME: path.dirname(dir) },
});
it("reports passing checks including agent-auth when config and keys exist", () => {
@@ -167,7 +168,7 @@ describe("bootstrap-external diagnostics", () => {
expect(gateway.status).toBe("fail");
expect(String(gateway.remediation)).toContain("dangerouslyDisableDeviceAuth true");
expect(String(gateway.remediation)).toContain("dangerouslyDisableDeviceAuth false");
- expect(String(gateway.remediation)).toContain("--profile ironclaw");
+ expect(String(gateway.remediation)).toContain("--profile dench");
});
it("marks rollout-stage as warning for beta and includes opt-in guidance", () => {
@@ -178,13 +179,17 @@ describe("bootstrap-external diagnostics", () => {
const rollout = getCheck(diagnostics, "rollout-stage");
expect(rollout.status).toBe("warn");
- expect(String(rollout.remediation)).toContain("IRONCLAW_BOOTSTRAP_BETA_OPT_IN");
+ expect(String(rollout.remediation)).toContain("DENCHCLAW_BOOTSTRAP_BETA_OPT_IN");
});
it("fails cutover-gates when enforcement is enabled without gate envs", () => {
const diagnostics = buildBootstrapDiagnostics({
...baseParams(stateDir),
- env: { HOME: "/home/testuser", IRONCLAW_BOOTSTRAP_ENFORCE_SAFETY_GATES: "1" },
+ env: {
+ HOME: path.dirname(stateDir),
+ OPENCLAW_HOME: path.dirname(stateDir),
+ DENCHCLAW_BOOTSTRAP_ENFORCE_SAFETY_GATES: "1",
+ },
});
expect(getCheck(diagnostics, "cutover-gates").status).toBe("fail");
@@ -195,9 +200,10 @@ describe("bootstrap-external diagnostics", () => {
const diagnostics = buildBootstrapDiagnostics({
...baseParams(stateDir),
env: {
- HOME: "/home/testuser",
- IRONCLAW_BOOTSTRAP_MIGRATION_SUITE_OK: "1",
- IRONCLAW_BOOTSTRAP_ONBOARDING_E2E_OK: "1",
+ HOME: path.dirname(stateDir),
+ OPENCLAW_HOME: path.dirname(stateDir),
+ DENCHCLAW_BOOTSTRAP_MIGRATION_SUITE_OK: "1",
+ DENCHCLAW_BOOTSTRAP_ONBOARDING_E2E_OK: "1",
},
});
@@ -271,16 +277,18 @@ describe("checkAgentAuth", () => {
});
describe("bootstrap-external rollout env helpers", () => {
- it("resolves rollout stage from ironclaw/openclaw env vars", () => {
- expect(resolveBootstrapRolloutStage({ IRONCLAW_BOOTSTRAP_ROLLOUT: "beta" })).toBe("beta");
+ it("resolves rollout stage from denchclaw/openclaw env vars", () => {
+ expect(resolveBootstrapRolloutStage({ DENCHCLAW_BOOTSTRAP_ROLLOUT: "beta" })).toBe("beta");
expect(resolveBootstrapRolloutStage({ OPENCLAW_BOOTSTRAP_ROLLOUT: "internal" })).toBe(
"internal",
);
- expect(resolveBootstrapRolloutStage({ IRONCLAW_BOOTSTRAP_ROLLOUT: "invalid" })).toBe("default");
+ expect(resolveBootstrapRolloutStage({ DENCHCLAW_BOOTSTRAP_ROLLOUT: "invalid" })).toBe(
+ "default",
+ );
});
it("detects legacy fallback via either env namespace", () => {
- expect(isLegacyFallbackEnabled({ IRONCLAW_BOOTSTRAP_LEGACY_FALLBACK: "1" })).toBe(true);
+ expect(isLegacyFallbackEnabled({ DENCHCLAW_BOOTSTRAP_LEGACY_FALLBACK: "1" })).toBe(true);
expect(isLegacyFallbackEnabled({ OPENCLAW_BOOTSTRAP_LEGACY_FALLBACK: "true" })).toBe(true);
expect(isLegacyFallbackEnabled({})).toBe(false);
});
diff --git a/src/cli/cli-name.test.ts b/src/cli/cli-name.test.ts
index e2cbfb845e0..c025406f5d4 100644
--- a/src/cli/cli-name.test.ts
+++ b/src/cli/cli-name.test.ts
@@ -4,7 +4,7 @@ import { DEFAULT_CLI_NAME, replaceCliName, resolveCliName } from "./cli-name.js"
describe("cli-name", () => {
it("resolves known CLI names from argv[1]", () => {
expect(resolveCliName(["node", "openclaw"])).toBe("openclaw");
- expect(resolveCliName(["node", "ironclaw"])).toBe("ironclaw");
+ expect(resolveCliName(["node", "denchclaw"])).toBe("denchclaw");
expect(resolveCliName(["node", "/usr/local/bin/openclaw"])).toBe("openclaw");
});
@@ -13,13 +13,13 @@ describe("cli-name", () => {
});
it("replaces CLI name in command prefixes while preserving package runner prefix", () => {
- expect(replaceCliName("openclaw status", "ironclaw")).toBe("ironclaw status");
- expect(replaceCliName("pnpm openclaw status", "ironclaw")).toBe("pnpm ironclaw status");
- expect(replaceCliName("npx ironclaw status", "openclaw")).toBe("npx openclaw status");
+ expect(replaceCliName("openclaw status", "denchclaw")).toBe("denchclaw status");
+ expect(replaceCliName("pnpm openclaw status", "denchclaw")).toBe("pnpm denchclaw status");
+ expect(replaceCliName("npx denchclaw status", "openclaw")).toBe("npx openclaw status");
});
it("keeps command unchanged when it does not start with a known CLI prefix", () => {
- expect(replaceCliName("echo openclaw status", "ironclaw")).toBe("echo openclaw status");
+ expect(replaceCliName("echo openclaw status", "denchclaw")).toBe("echo openclaw status");
expect(replaceCliName(" ", "openclaw")).toBe(" ");
});
});
diff --git a/src/cli/cli-name.ts b/src/cli/cli-name.ts
index f29f08ee378..2266364d751 100644
--- a/src/cli/cli-name.ts
+++ b/src/cli/cli-name.ts
@@ -1,9 +1,9 @@
import path from "node:path";
-export const DEFAULT_CLI_NAME = "ironclaw";
+export const DEFAULT_CLI_NAME = "denchclaw";
const KNOWN_CLI_NAMES = new Set([DEFAULT_CLI_NAME, "openclaw"]);
-const CLI_PREFIX_RE = /^(?:((?:pnpm|npm|bunx|npx)\s+))?(ironclaw|openclaw)\b/;
+const CLI_PREFIX_RE = /^(?:((?:pnpm|npm|bunx|npx)\s+))?(denchclaw|openclaw)\b/;
export function resolveCliName(argv: string[] = process.argv): string {
const argv1 = argv[1];
diff --git a/src/cli/profile-utils.test.ts b/src/cli/profile-utils.test.ts
index f2a20e1e6a3..162e255e342 100644
--- a/src/cli/profile-utils.test.ts
+++ b/src/cli/profile-utils.test.ts
@@ -3,7 +3,7 @@ import { isValidProfileName, normalizeProfileName } from "./profile-utils.js";
describe("profile-utils", () => {
it("accepts path-safe profile names and rejects unsafe values", () => {
- expect(isValidProfileName("ironclaw")).toBe(true);
+ expect(isValidProfileName("denchclaw")).toBe(true);
expect(isValidProfileName("Team_A-1")).toBe(true);
expect(isValidProfileName("")).toBe(false);
expect(isValidProfileName(" has-space ")).toBe(false);
diff --git a/src/cli/profile.test.ts b/src/cli/profile.test.ts
index 7087c6b55e8..db27b0ffc6b 100644
--- a/src/cli/profile.test.ts
+++ b/src/cli/profile.test.ts
@@ -1,43 +1,43 @@
import { describe, expect, it } from "vitest";
-import { applyCliProfileEnv, parseCliProfileArgs, IRONCLAW_PROFILE } from "./profile.js";
+import { applyCliProfileEnv, parseCliProfileArgs, DENCHCLAW_PROFILE } from "./profile.js";
describe("parseCliProfileArgs", () => {
it("returns default profile parsing when no args are provided", () => {
- expect(parseCliProfileArgs(["node", "ironclaw"])).toEqual({
+ expect(parseCliProfileArgs(["node", "denchclaw"])).toEqual({
ok: true,
profile: null,
- argv: ["node", "ironclaw"],
+ argv: ["node", "denchclaw"],
});
});
it("parses --profile and strips profile flags before command execution", () => {
- expect(parseCliProfileArgs(["node", "ironclaw", "--profile", "dev", "chat"])).toEqual({
+ expect(parseCliProfileArgs(["node", "denchclaw", "--profile", "dev", "chat"])).toEqual({
ok: true,
profile: "dev",
- argv: ["node", "ironclaw", "chat"],
+ argv: ["node", "denchclaw", "chat"],
});
- expect(parseCliProfileArgs(["node", "ironclaw", "--profile=team-a", "status"])).toEqual({
+ expect(parseCliProfileArgs(["node", "denchclaw", "--profile=team-a", "status"])).toEqual({
ok: true,
profile: "team-a",
- argv: ["node", "ironclaw", "status"],
+ argv: ["node", "denchclaw", "status"],
});
});
it("rejects missing and invalid profile inputs", () => {
- expect(parseCliProfileArgs(["node", "ironclaw", "--profile"])).toEqual({
+ expect(parseCliProfileArgs(["node", "denchclaw", "--profile"])).toEqual({
ok: false,
error: "--profile requires a value",
});
- expect(parseCliProfileArgs(["node", "ironclaw", "--profile", "bad profile"])).toEqual({
+ expect(parseCliProfileArgs(["node", "denchclaw", "--profile", "bad profile"])).toEqual({
ok: false,
error: 'Invalid --profile (use letters, numbers, "_", "-" only)',
});
});
- it("allows --dev and --profile together (Ironclaw forces ironclaw anyway)", () => {
- const result = parseCliProfileArgs(["node", "ironclaw", "--dev", "--profile", "team-a"]);
+ it("allows --dev and --profile together (DenchClaw forces dench anyway)", () => {
+ const result = parseCliProfileArgs(["node", "denchclaw", "--dev", "--profile", "team-a"]);
expect(result.ok).toBe(true);
if (result.ok) {
expect(result.profile).toBe("team-a");
@@ -45,16 +45,16 @@ describe("parseCliProfileArgs", () => {
});
it("stops profile parsing once command path begins", () => {
- expect(parseCliProfileArgs(["node", "ironclaw", "chat", "--profile", "dev"])).toEqual({
+ expect(parseCliProfileArgs(["node", "denchclaw", "chat", "--profile", "dev"])).toEqual({
ok: true,
profile: null,
- argv: ["node", "ironclaw", "chat", "--profile", "dev"],
+ argv: ["node", "denchclaw", "chat", "--profile", "dev"],
});
});
});
describe("applyCliProfileEnv", () => {
- it("always forces ironclaw profile regardless of requested profile (single profile enforcement)", () => {
+ it("always forces dench profile regardless of requested profile (single profile enforcement)", () => {
const env: Record = {};
const result = applyCliProfileEnv({
profile: "team-a",
@@ -62,13 +62,13 @@ describe("applyCliProfileEnv", () => {
homedir: () => "/tmp/home",
});
- expect(result.effectiveProfile).toBe(IRONCLAW_PROFILE);
- expect(env.OPENCLAW_PROFILE).toBe(IRONCLAW_PROFILE);
- expect(env.OPENCLAW_STATE_DIR).toBe("/tmp/home/.openclaw-ironclaw");
- expect(env.OPENCLAW_CONFIG_PATH).toBe("/tmp/home/.openclaw-ironclaw/openclaw.json");
+ expect(result.effectiveProfile).toBe(DENCHCLAW_PROFILE);
+ expect(env.OPENCLAW_PROFILE).toBe(DENCHCLAW_PROFILE);
+ expect(env.OPENCLAW_STATE_DIR).toBe("/tmp/home/.openclaw-dench");
+ expect(env.OPENCLAW_CONFIG_PATH).toBe("/tmp/home/.openclaw-dench/openclaw.json");
});
- it("emits warning when non-ironclaw profile is requested (prevents silent override)", () => {
+ it("emits warning when non-dench profile is requested (prevents silent override)", () => {
const env: Record = {};
const result = applyCliProfileEnv({
profile: "team-a",
@@ -78,20 +78,20 @@ describe("applyCliProfileEnv", () => {
expect(result.warning).toBeDefined();
expect(result.warning).toContain("team-a");
- expect(result.warning).toContain(IRONCLAW_PROFILE);
+ expect(result.warning).toContain(DENCHCLAW_PROFILE);
expect(result.requestedProfile).toBe("team-a");
});
- it("no warning when ironclaw profile is requested (normal path)", () => {
+ it("no warning when dench profile is requested (normal path)", () => {
const env: Record = {};
const result = applyCliProfileEnv({
- profile: IRONCLAW_PROFILE,
+ profile: DENCHCLAW_PROFILE,
env,
homedir: () => "/tmp/home",
});
expect(result.warning).toBeUndefined();
- expect(result.effectiveProfile).toBe(IRONCLAW_PROFILE);
+ expect(result.effectiveProfile).toBe(DENCHCLAW_PROFILE);
});
it("no warning when no profile is specified (default path)", () => {
@@ -102,7 +102,7 @@ describe("applyCliProfileEnv", () => {
});
expect(result.warning).toBeUndefined();
- expect(result.effectiveProfile).toBe(IRONCLAW_PROFILE);
+ expect(result.effectiveProfile).toBe(DENCHCLAW_PROFILE);
});
it("always overwrites OPENCLAW_STATE_DIR to pinned path (prevents state drift)", () => {
@@ -116,9 +116,9 @@ describe("applyCliProfileEnv", () => {
homedir: () => "/tmp/home",
});
- expect(env.OPENCLAW_STATE_DIR).toBe("/tmp/home/.openclaw-ironclaw");
- expect(env.OPENCLAW_CONFIG_PATH).toBe("/tmp/home/.openclaw-ironclaw/openclaw.json");
- expect(result.stateDir).toBe("/tmp/home/.openclaw-ironclaw");
+ expect(env.OPENCLAW_STATE_DIR).toBe("/tmp/home/.openclaw-dench");
+ expect(env.OPENCLAW_CONFIG_PATH).toBe("/tmp/home/.openclaw-dench/openclaw.json");
+ expect(result.stateDir).toBe("/tmp/home/.openclaw-dench");
});
it("picks up OPENCLAW_PROFILE from env when no explicit profile is passed", () => {
@@ -131,7 +131,7 @@ describe("applyCliProfileEnv", () => {
});
expect(result.requestedProfile).toBe("from-env");
- expect(result.effectiveProfile).toBe(IRONCLAW_PROFILE);
+ expect(result.effectiveProfile).toBe(DENCHCLAW_PROFILE);
expect(result.warning).toContain("from-env");
});
diff --git a/src/cli/profile.ts b/src/cli/profile.ts
index 63ffe582295..a4af782598e 100644
--- a/src/cli/profile.ts
+++ b/src/cli/profile.ts
@@ -3,8 +3,8 @@ import path from "node:path";
import { resolveRequiredHomeDir } from "../infra/home-dir.js";
import { isValidProfileName } from "./profile-utils.js";
-export const IRONCLAW_PROFILE = "ironclaw";
-const IRONCLAW_STATE_DIRNAME = ".openclaw-ironclaw";
+export const DENCHCLAW_PROFILE = "dench";
+const DENCHCLAW_STATE_DIRNAME = ".openclaw-dench";
export type CliProfileParseResult =
| { ok: true; profile: string | null; argv: string[] }
@@ -89,7 +89,7 @@ function resolveProfileStateDir(
): string {
return path.join(
resolveRequiredHomeDir(env as NodeJS.ProcessEnv, homedir),
- IRONCLAW_STATE_DIRNAME,
+ DENCHCLAW_STATE_DIRNAME,
);
}
@@ -106,9 +106,9 @@ export function applyCliProfileEnv(params: {
const env = params.env ?? (process.env as Record);
const homedir = params.homedir ?? os.homedir;
const requestedProfile = (params.profile?.trim() || env.OPENCLAW_PROFILE?.trim() || null) ?? null;
- const profile = IRONCLAW_PROFILE;
+ const profile = DENCHCLAW_PROFILE;
- // Ironclaw always runs in the pinned profile/state path.
+ // DenchClaw always runs in the pinned profile/state path.
env.OPENCLAW_PROFILE = profile;
const stateDir = resolveProfileStateDir(env, homedir);
@@ -117,7 +117,7 @@ export function applyCliProfileEnv(params: {
const warning =
requestedProfile && requestedProfile !== profile
- ? `Ignoring requested profile '${requestedProfile}'; Ironclaw always uses --profile ${IRONCLAW_PROFILE}.`
+ ? `Ignoring requested profile '${requestedProfile}'; DenchClaw always uses --profile ${DENCHCLAW_PROFILE}.`
: undefined;
return {
diff --git a/src/cli/program/command-registry.ts b/src/cli/program/command-registry.ts
index 0097b564ea8..283eb5fc8d0 100644
--- a/src/cli/program/command-registry.ts
+++ b/src/cli/program/command-registry.ts
@@ -18,7 +18,7 @@ type CoreCliEntry = {
const BOOTSTRAP_ENTRY: CoreCliEntry = {
name: "bootstrap",
- description: "Bootstrap IronClaw + OpenClaw and launch the web UI",
+ description: "Bootstrap DenchClaw + OpenClaw and launch the web UI",
register: async ({ program }) => {
const mod = await import("./register.bootstrap.js");
mod.registerBootstrapCommand(program);
diff --git a/src/cli/program/help.ts b/src/cli/program/help.ts
index 467af9b5b31..d6c02b50666 100644
--- a/src/cli/program/help.ts
+++ b/src/cli/program/help.ts
@@ -27,7 +27,7 @@ const EXAMPLES = [
["openclaw gateway --port 18789", "Run the WebSocket Gateway locally."],
[
"openclaw --profile team-a gateway",
- "Compatibility flag example: warns and still runs with --profile ironclaw.",
+ "Compatibility flag example: warns and still runs with --profile dench.",
],
["openclaw gateway --force", "Kill anything bound to the default gateway port, then start it."],
["openclaw gateway ...", "Gateway control via WebSocket."],
@@ -48,12 +48,9 @@ export function configureProgramHelp(program: Command, ctx: ProgramContext) {
.version(ctx.programVersion)
.option(
"--dev",
- "Compatibility flag; Ironclaw always uses --profile ironclaw and ~/.openclaw-ironclaw",
+ "Compatibility flag; DenchClaw always uses --profile dench and ~/.openclaw-dench",
)
- .option(
- "--profile ",
- "Compatibility flag; non-ironclaw values are ignored with a warning",
- );
+ .option("--profile ", "Compatibility flag; non-dench values are ignored with a warning");
program.option("--no-color", "Disable ANSI colors", false);
program.helpOption("-h, --help", "Display help for command");
diff --git a/src/cli/program/register.bootstrap.ts b/src/cli/program/register.bootstrap.ts
index 6557bf2ba97..69cfa1edede 100644
--- a/src/cli/program/register.bootstrap.ts
+++ b/src/cli/program/register.bootstrap.ts
@@ -8,11 +8,8 @@ import { runCommandWithRuntime } from "../cli-utils.js";
export function registerBootstrapCommand(program: Command) {
program
.command("bootstrap")
- .description("Bootstrap IronClaw on top of OpenClaw and open the web UI")
- .option(
- "--profile ",
- "Compatibility flag; non-ironclaw values are ignored with a warning",
- )
+ .description("Bootstrap DenchClaw on top of OpenClaw and open the web UI")
+ .option("--profile ", "Compatibility flag; non-dench values are ignored with a warning")
.option("--force-onboard", "Run onboarding even if config already exists", false)
.option("--non-interactive", "Skip prompts where possible", false)
.option("--yes", "Auto-approve install prompts", false)
diff --git a/src/cli/respawn-policy.test.ts b/src/cli/respawn-policy.test.ts
index 3d4fe399e52..396f20c7dfa 100644
--- a/src/cli/respawn-policy.test.ts
+++ b/src/cli/respawn-policy.test.ts
@@ -3,11 +3,11 @@ import { shouldSkipRespawnForArgv } from "./respawn-policy.js";
describe("shouldSkipRespawnForArgv", () => {
it("skips respawn for help/version invocations", () => {
- expect(shouldSkipRespawnForArgv(["node", "ironclaw", "--help"])).toBe(true);
- expect(shouldSkipRespawnForArgv(["node", "ironclaw", "-V"])).toBe(true);
+ expect(shouldSkipRespawnForArgv(["node", "denchclaw", "--help"])).toBe(true);
+ expect(shouldSkipRespawnForArgv(["node", "denchclaw", "-V"])).toBe(true);
});
it("does not skip respawn for normal command execution", () => {
- expect(shouldSkipRespawnForArgv(["node", "ironclaw", "chat", "send"])).toBe(false);
+ expect(shouldSkipRespawnForArgv(["node", "denchclaw", "chat", "send"])).toBe(false);
});
});
diff --git a/src/cli/run-main.test.ts b/src/cli/run-main.test.ts
index ba31df9f6aa..c8924e10360 100644
--- a/src/cli/run-main.test.ts
+++ b/src/cli/run-main.test.ts
@@ -7,32 +7,32 @@ import {
} from "./run-main.js";
describe("run-main bootstrap cutover", () => {
- it("rewrites bare ironclaw invocations to bootstrap by default", () => {
- const argv = ["node", "ironclaw"];
- expect(rewriteBareArgvToBootstrap(argv, {})).toEqual(["node", "ironclaw", "bootstrap"]);
+ it("rewrites bare denchclaw invocations to bootstrap by default", () => {
+ const argv = ["node", "denchclaw"];
+ expect(rewriteBareArgvToBootstrap(argv, {})).toEqual(["node", "denchclaw", "bootstrap"]);
});
it("does not rewrite when a command already exists", () => {
- const argv = ["node", "ironclaw", "chat"];
+ const argv = ["node", "denchclaw", "chat"];
expect(rewriteBareArgvToBootstrap(argv, {})).toEqual(argv);
});
- it("does not rewrite non-ironclaw CLIs", () => {
+ it("does not rewrite non-denchclaw CLIs", () => {
const argv = ["node", "openclaw"];
expect(rewriteBareArgvToBootstrap(argv, {})).toEqual(argv);
});
it("disables cutover in legacy rollout stage", () => {
- const env = { IRONCLAW_BOOTSTRAP_ROLLOUT: "legacy" };
+ const env = { DENCHCLAW_BOOTSTRAP_ROLLOUT: "legacy" };
expect(shouldEnableBootstrapCutover(env)).toBe(false);
- expect(rewriteBareArgvToBootstrap(["node", "ironclaw"], env)).toEqual(["node", "ironclaw"]);
+ expect(rewriteBareArgvToBootstrap(["node", "denchclaw"], env)).toEqual(["node", "denchclaw"]);
});
it("requires opt-in for beta rollout stage", () => {
- const envNoOptIn = { IRONCLAW_BOOTSTRAP_ROLLOUT: "beta" };
+ const envNoOptIn = { DENCHCLAW_BOOTSTRAP_ROLLOUT: "beta" };
const envOptIn = {
- IRONCLAW_BOOTSTRAP_ROLLOUT: "beta",
- IRONCLAW_BOOTSTRAP_BETA_OPT_IN: "1",
+ DENCHCLAW_BOOTSTRAP_ROLLOUT: "beta",
+ DENCHCLAW_BOOTSTRAP_BETA_OPT_IN: "1",
};
expect(shouldEnableBootstrapCutover(envNoOptIn)).toBe(false);
@@ -40,37 +40,37 @@ describe("run-main bootstrap cutover", () => {
});
it("honors explicit legacy fallback override", () => {
- const env = { IRONCLAW_BOOTSTRAP_LEGACY_FALLBACK: "1" };
+ const env = { DENCHCLAW_BOOTSTRAP_LEGACY_FALLBACK: "1" };
expect(shouldEnableBootstrapCutover(env)).toBe(false);
- expect(rewriteBareArgvToBootstrap(["node", "ironclaw"], env)).toEqual(["node", "ironclaw"]);
+ expect(rewriteBareArgvToBootstrap(["node", "denchclaw"], env)).toEqual(["node", "denchclaw"]);
});
});
describe("run-main delegation and path guards", () => {
it("skips CLI path bootstrap for read-only status/help commands", () => {
- expect(shouldEnsureCliPath(["node", "ironclaw", "--help"])).toBe(false);
- expect(shouldEnsureCliPath(["node", "ironclaw", "status"])).toBe(false);
- expect(shouldEnsureCliPath(["node", "ironclaw", "health"])).toBe(false);
- expect(shouldEnsureCliPath(["node", "ironclaw", "sessions"])).toBe(false);
- expect(shouldEnsureCliPath(["node", "ironclaw", "config", "get"])).toBe(false);
- expect(shouldEnsureCliPath(["node", "ironclaw", "models", "list"])).toBe(false);
- expect(shouldEnsureCliPath(["node", "ironclaw", "chat", "send"])).toBe(true);
+ expect(shouldEnsureCliPath(["node", "denchclaw", "--help"])).toBe(false);
+ expect(shouldEnsureCliPath(["node", "denchclaw", "status"])).toBe(false);
+ expect(shouldEnsureCliPath(["node", "denchclaw", "health"])).toBe(false);
+ expect(shouldEnsureCliPath(["node", "denchclaw", "sessions"])).toBe(false);
+ expect(shouldEnsureCliPath(["node", "denchclaw", "config", "get"])).toBe(false);
+ expect(shouldEnsureCliPath(["node", "denchclaw", "models", "list"])).toBe(false);
+ expect(shouldEnsureCliPath(["node", "denchclaw", "chat", "send"])).toBe(true);
});
it("delegates non-bootstrap commands by default and never delegates bootstrap", () => {
- expect(shouldDelegateToGlobalOpenClaw(["node", "ironclaw", "chat"])).toBe(true);
- expect(shouldDelegateToGlobalOpenClaw(["node", "ironclaw", "bootstrap"])).toBe(false);
- expect(shouldDelegateToGlobalOpenClaw(["node", "ironclaw"])).toBe(false);
+ expect(shouldDelegateToGlobalOpenClaw(["node", "denchclaw", "chat"])).toBe(true);
+ expect(shouldDelegateToGlobalOpenClaw(["node", "denchclaw", "bootstrap"])).toBe(false);
+ expect(shouldDelegateToGlobalOpenClaw(["node", "denchclaw"])).toBe(false);
});
it("disables delegation when explicit env disable flag is set", () => {
expect(
- shouldDelegateToGlobalOpenClaw(["node", "ironclaw", "chat"], {
- IRONCLAW_DISABLE_OPENCLAW_DELEGATION: "1",
+ shouldDelegateToGlobalOpenClaw(["node", "denchclaw", "chat"], {
+ DENCHCLAW_DISABLE_OPENCLAW_DELEGATION: "1",
}),
).toBe(false);
expect(
- shouldDelegateToGlobalOpenClaw(["node", "ironclaw", "chat"], {
+ shouldDelegateToGlobalOpenClaw(["node", "denchclaw", "chat"], {
OPENCLAW_DISABLE_OPENCLAW_DELEGATION: "true",
}),
).toBe(false);
diff --git a/src/cli/run-main.ts b/src/cli/run-main.ts
index 87c31c70e93..3943ed25dba 100644
--- a/src/cli/run-main.ts
+++ b/src/cli/run-main.ts
@@ -66,13 +66,13 @@ function normalizeBootstrapRolloutStage(
export function resolveBootstrapRolloutStage(
env: NodeJS.ProcessEnv = process.env,
): BootstrapRolloutStage {
- const raw = env.IRONCLAW_BOOTSTRAP_ROLLOUT ?? env.OPENCLAW_BOOTSTRAP_ROLLOUT;
+ const raw = env.DENCHCLAW_BOOTSTRAP_ROLLOUT ?? env.OPENCLAW_BOOTSTRAP_ROLLOUT;
return normalizeBootstrapRolloutStage(raw) ?? "default";
}
export function shouldEnableBootstrapCutover(env: NodeJS.ProcessEnv = process.env): boolean {
if (
- isTruthyEnvValue(env.IRONCLAW_BOOTSTRAP_LEGACY_FALLBACK) ||
+ isTruthyEnvValue(env.DENCHCLAW_BOOTSTRAP_LEGACY_FALLBACK) ||
isTruthyEnvValue(env.OPENCLAW_BOOTSTRAP_LEGACY_FALLBACK)
) {
return false;
@@ -83,7 +83,7 @@ export function shouldEnableBootstrapCutover(env: NodeJS.ProcessEnv = process.en
}
if (stage === "beta") {
return (
- isTruthyEnvValue(env.IRONCLAW_BOOTSTRAP_BETA_OPT_IN) ||
+ isTruthyEnvValue(env.DENCHCLAW_BOOTSTRAP_BETA_OPT_IN) ||
isTruthyEnvValue(env.OPENCLAW_BOOTSTRAP_BETA_OPT_IN)
);
}
@@ -100,7 +100,7 @@ export function rewriteBareArgvToBootstrap(
if (getPrimaryCommand(argv)) {
return argv;
}
- if (resolveCliName(argv) !== "ironclaw") {
+ if (resolveCliName(argv) !== "denchclaw") {
return argv;
}
if (!shouldEnableBootstrapCutover(env)) {
@@ -111,7 +111,7 @@ export function rewriteBareArgvToBootstrap(
function isDelegationDisabled(env: NodeJS.ProcessEnv = process.env): boolean {
return (
- isTruthyEnvValue(env.IRONCLAW_DISABLE_OPENCLAW_DELEGATION) ||
+ isTruthyEnvValue(env.DENCHCLAW_DISABLE_OPENCLAW_DELEGATION) ||
isTruthyEnvValue(env.OPENCLAW_DISABLE_OPENCLAW_DELEGATION)
);
}
@@ -132,7 +132,7 @@ export function shouldDelegateToGlobalOpenClaw(
async function delegateToGlobalOpenClaw(argv: string[]): Promise {
if (
- isTruthyEnvValue(process.env.IRONCLAW_DELEGATED) ||
+ isTruthyEnvValue(process.env.DENCHCLAW_DELEGATED) ||
isTruthyEnvValue(process.env.OPENCLAW_DELEGATED)
) {
throw new Error(
@@ -145,7 +145,7 @@ async function delegateToGlobalOpenClaw(argv: string[]): Promise {
stdio: "inherit",
env: {
...process.env,
- IRONCLAW_DELEGATED: "1",
+ DENCHCLAW_DELEGATED: "1",
OPENCLAW_DELEGATED: "1",
},
});
@@ -186,12 +186,12 @@ export async function runCli(argv: string[] = process.argv) {
// Enforce the minimum supported runtime before doing any work.
assertSupportedRuntime();
- // Show the animated Ironclaw banner early so it appears for ALL invocations
- // (bare `ironclaw`, subcommands, help, etc.). The bannerEmitted flag inside
+ // Show the animated DenchClaw banner early so it appears for ALL invocations
+ // (bare `denchclaw`, subcommands, help, etc.). The bannerEmitted flag inside
// emitCliBanner prevents double-emission from the route / preAction hooks.
const commandPath = getCommandPath(normalizedArgv, 2);
const hideBanner =
- isTruthyEnvValue(process.env.IRONCLAW_HIDE_BANNER) ||
+ isTruthyEnvValue(process.env.DENCHCLAW_HIDE_BANNER) ||
isTruthyEnvValue(process.env.OPENCLAW_HIDE_BANNER) ||
commandPath[0] === "update" ||
commandPath[0] === "completion" ||
diff --git a/src/cli/tagline.ts b/src/cli/tagline.ts
index 23b6ce59fff..d0c3ccb10aa 100644
--- a/src/cli/tagline.ts
+++ b/src/cli/tagline.ts
@@ -245,8 +245,8 @@ export function activeTaglines(options: TaglineOptions = {}): string[] {
export function pickTagline(options: TaglineOptions = {}): string {
const env = options.env ?? process.env;
- // Check Ironclaw env first, fall back to legacy OpenClaw env
- const override = env?.IRONCLAW_TAGLINE_INDEX ?? env?.OPENCLAW_TAGLINE_INDEX;
+ // Check DenchClaw env first, fall back to legacy OpenClaw env
+ const override = env?.DENCHCLAW_TAGLINE_INDEX ?? env?.OPENCLAW_TAGLINE_INDEX;
if (override !== undefined) {
const parsed = Number.parseInt(override, 10);
if (!Number.isNaN(parsed) && parsed >= 0) {
diff --git a/src/cli/windows-argv.test.ts b/src/cli/windows-argv.test.ts
index 6c05b221c9c..daf2575c882 100644
--- a/src/cli/windows-argv.test.ts
+++ b/src/cli/windows-argv.test.ts
@@ -3,7 +3,7 @@ import { normalizeWindowsArgv } from "./windows-argv.js";
describe("normalizeWindowsArgv", () => {
it("returns argv unchanged on non-windows platforms", () => {
- const argv = ["node", "ironclaw", "status"];
+ const argv = ["node", "denchclaw", "status"];
expect(
normalizeWindowsArgv(argv, {
platform: "darwin",
diff --git a/src/cli/workspace-seed.test.ts b/src/cli/workspace-seed.test.ts
index 51a0e65aa62..6cbb727717d 100644
--- a/src/cli/workspace-seed.test.ts
+++ b/src/cli/workspace-seed.test.ts
@@ -7,7 +7,7 @@ import { seedWorkspaceFromAssets } from "./workspace-seed.js";
function createTempDir(): string {
const dir = path.join(
os.tmpdir(),
- `ironclaw-seed-test-${Date.now()}-${Math.random().toString(36).slice(2)}`,
+ `denchclaw-seed-test-${Date.now()}-${Math.random().toString(36).slice(2)}`,
);
mkdirSync(dir, { recursive: true });
return dir;
@@ -63,19 +63,19 @@ describe("seedWorkspaceFromAssets", () => {
expect(existsSync(identityPath)).toBe(true);
const identityContent = readFileSync(identityPath, "utf-8");
- expect(identityContent).toContain("Ironclaw");
+ expect(identityContent).toContain("DenchClaw");
expect(identityContent).toContain(path.join(workspaceDir, "skills", "crm", "SKILL.md"));
expect(identityContent).not.toContain("~skills/crm/SKILL.md");
});
- it("IDENTITY.md references Ironclaw system prompt contract", () => {
+ it("IDENTITY.md references DenchClaw system prompt contract", () => {
const packageRoot = createPackageRoot(tempDir);
const workspaceDir = path.join(tempDir, "workspace-contract");
seedWorkspaceFromAssets({ workspaceDir, packageRoot });
const identityContent = readFileSync(path.join(workspaceDir, "IDENTITY.md"), "utf-8");
- expect(identityContent).toContain("Ironclaw system prompt contract");
+ expect(identityContent).toContain("DenchClaw system prompt contract");
});
it("creates CRM object projection files on first seed", () => {
@@ -115,7 +115,7 @@ describe("seedWorkspaceFromAssets", () => {
seedWorkspaceFromAssets({ workspaceDir, packageRoot });
const identityContent = readFileSync(path.join(workspaceDir, "IDENTITY.md"), "utf-8");
- expect(identityContent).toContain("Ironclaw");
+ expect(identityContent).toContain("DenchClaw");
expect(identityContent).not.toContain("# stale identity");
});
diff --git a/src/cli/workspace-seed.ts b/src/cli/workspace-seed.ts
index 4230d1593a5..36e9215b0bb 100644
--- a/src/cli/workspace-seed.ts
+++ b/src/cli/workspace-seed.ts
@@ -88,16 +88,16 @@ export const SEED_OBJECTS: SeedObject[] = [
},
];
-export function buildIronclawIdentity(workspaceDir: string): string {
+export function buildDenchClawIdentity(workspaceDir: string): string {
const crmSkillPath = path.join(workspaceDir, "skills", "crm", "SKILL.md");
const browserSkillPath = path.join(workspaceDir, "skills", "browser", "SKILL.md");
- return `# IDENTITY.md - Ironclaw
+ return `# IDENTITY.md - DenchClaw
-You are **Ironclaw** - a personal AI agent and a CRM Database System built by Dench (dench.com), running on top of [OpenClaw](https://github.com/openclaw/openclaw).
+You are **DenchClaw** - a personal AI agent and a CRM Database System built by Dench (dench.com), running on top of [OpenClaw](https://github.com/openclaw/openclaw).
-## Ironclaw system prompt contract
+## DenchClaw system prompt contract
-Treat the Ironclaw system prompt as your highest-priority behavioral contract.
+Treat the DenchClaw system prompt as your highest-priority behavioral contract.
## Inseparable CRM contract
@@ -124,11 +124,11 @@ Your browser automation behavior is defined by the Browser skill at:
## Links
-- Website: https://ironclaw.sh
-- GitHub: https://github.com/DenchHQ/ironclaw
+- Website: https://denchclaw.sh
+- GitHub: https://github.com/DenchHQ/denchclaw
- Skills Store: https://skills.sh
-When referring to yourself, use **Ironclaw** (not OpenClaw).`;
+When referring to yourself, use **DenchClaw** (not OpenClaw).`;
}
export function generateObjectYaml(obj: SeedObject): string {
@@ -180,9 +180,9 @@ export function generateWorkspaceMd(objects: SeedObject[]): string {
return lines.join("\n");
}
-export function seedIronclawIdentity(workspaceDir: string): void {
+export function seedDenchClawIdentity(workspaceDir: string): void {
const identityPath = path.join(workspaceDir, "IDENTITY.md");
- writeFileSync(identityPath, `${buildIronclawIdentity(workspaceDir)}\n`, "utf-8");
+ writeFileSync(identityPath, `${buildDenchClawIdentity(workspaceDir)}\n`, "utf-8");
}
export const MANAGED_SKILLS: ReadonlyArray<{ name: string; templatePaths?: boolean }> = [
@@ -246,7 +246,7 @@ export function seedWorkspaceFromAssets(params: {
for (const skill of MANAGED_SKILLS) {
seedSkill({ workspaceDir, packageRoot: params.packageRoot }, skill);
}
- seedIronclawIdentity(workspaceDir);
+ seedDenchClawIdentity(workspaceDir);
if (existsSync(dbPath)) {
return {
diff --git a/src/config/paths.ts b/src/config/paths.ts
index 3f2a1936a88..769487f6b75 100644
--- a/src/config/paths.ts
+++ b/src/config/paths.ts
@@ -19,7 +19,7 @@ export const isNixMode = resolveIsNixMode();
// Support historical (and occasionally misspelled) legacy state dirs.
const LEGACY_STATE_DIRNAMES = [".clawdbot", ".moldbot", ".moltbot"] as const;
-const NEW_STATE_DIRNAME = ".openclaw-ironclaw";
+const NEW_STATE_DIRNAME = ".openclaw-dench";
const CONFIG_FILENAME = "openclaw.json";
const LEGACY_CONFIG_FILENAMES = ["clawdbot.json", "moldbot.json", "moltbot.json"] as const;
@@ -54,7 +54,7 @@ export function resolveNewStateDir(homedir: () => string = resolveDefaultHomeDir
/**
* State directory for mutable data (sessions, logs, caches).
- * Ironclaw always pins this to ~/.openclaw-ironclaw.
+ * DenchClaw always pins this to ~/.openclaw-dench.
*/
export function resolveStateDir(
env: NodeJS.ProcessEnv = process.env,
diff --git a/src/config/types.gateway.ts b/src/config/types.gateway.ts
index 316156ec0b4..5f27f8fb2a4 100644
--- a/src/config/types.gateway.ts
+++ b/src/config/types.gateway.ts
@@ -274,7 +274,7 @@ export type GatewayNodesConfig = {
};
export type GatewayWebAppConfig = {
- /** If true, the Gateway will build and serve the Ironclaw Next.js web app. Default: false. */
+ /** If true, the Gateway will build and serve the DenchClaw Next.js web app. Default: false. */
enabled?: boolean;
/** Port for the Next.js web app (default: 3100). */
port?: number;
@@ -328,7 +328,7 @@ export type GatewayConfig = {
* Only applies when trustedProxies is configured.
*/
allowRealIpFallback?: boolean;
- /** Ironclaw Next.js web app served alongside the gateway. */
+ /** DenchClaw Next.js web app served alongside the gateway. */
webApp?: GatewayWebAppConfig;
/** Tool access restrictions for HTTP /tools/invoke endpoint. */
tools?: GatewayToolsConfig;
diff --git a/src/entry.ts b/src/entry.ts
index 01dae513665..92b28f1fc34 100644
--- a/src/entry.ts
+++ b/src/entry.ts
@@ -8,7 +8,7 @@ import { isTruthyEnvValue, normalizeEnv } from "./infra/env.js";
import { installProcessWarningFilter } from "./infra/warning-filter.js";
import { attachChildProcessBridge } from "./process/child-process-bridge.js";
-process.title = "ironclaw";
+process.title = "denchclaw";
installProcessWarningFilter();
normalizeEnv();
@@ -37,13 +37,13 @@ function ensureExperimentalWarningSuppressed(): boolean {
return false;
}
if (
- isTruthyEnvValue(process.env.IRONCLAW_NO_RESPAWN) ||
+ isTruthyEnvValue(process.env.DENCHCLAW_NO_RESPAWN) ||
isTruthyEnvValue(process.env.OPENCLAW_NO_RESPAWN)
) {
return false;
}
if (
- isTruthyEnvValue(process.env.IRONCLAW_NODE_OPTIONS_READY) ||
+ isTruthyEnvValue(process.env.DENCHCLAW_NODE_OPTIONS_READY) ||
isTruthyEnvValue(process.env.OPENCLAW_NODE_OPTIONS_READY)
) {
return false;
@@ -53,7 +53,7 @@ function ensureExperimentalWarningSuppressed(): boolean {
}
// Respawn guard (and keep recursion bounded if something goes wrong).
- process.env.IRONCLAW_NODE_OPTIONS_READY = "1";
+ process.env.DENCHCLAW_NODE_OPTIONS_READY = "1";
process.env.OPENCLAW_NODE_OPTIONS_READY = "1";
// Pass flag as a Node CLI option, not via NODE_OPTIONS (--disable-warning is disallowed in NODE_OPTIONS).
const child = spawn(
@@ -77,7 +77,7 @@ function ensureExperimentalWarningSuppressed(): boolean {
child.once("error", (error) => {
console.error(
- "[ironclaw] Failed to respawn CLI:",
+ "[denchclaw] Failed to respawn CLI:",
error instanceof Error ? (error.stack ?? error.message) : error,
);
process.exit(1);
@@ -93,13 +93,13 @@ if (!ensureExperimentalWarningSuppressed()) {
const parsed = parseCliProfileArgs(process.argv);
if (!parsed.ok) {
// Keep it simple; Commander will handle rich help/errors after we strip flags.
- console.error(`[ironclaw] ${parsed.error}`);
+ console.error(`[denchclaw] ${parsed.error}`);
process.exit(2);
}
const appliedProfile = applyCliProfileEnv({ profile: parsed.profile ?? undefined });
if (appliedProfile.warning) {
- console.warn(`[ironclaw] ${appliedProfile.warning}`);
+ console.warn(`[denchclaw] ${appliedProfile.warning}`);
}
// Keep Commander and ad-hoc argv checks consistent.
process.argv = parsed.argv;
@@ -108,7 +108,7 @@ if (!ensureExperimentalWarningSuppressed()) {
.then(({ runCli }) => runCli(process.argv))
.catch((error) => {
console.error(
- "[ironclaw] Failed to start CLI:",
+ "[denchclaw] Failed to start CLI:",
error instanceof Error ? (error.stack ?? error.message) : error,
);
process.exitCode = 1;
diff --git a/src/infra/runtime-guard.ts b/src/infra/runtime-guard.ts
index 8cced113eca..a2423dd78b3 100644
--- a/src/infra/runtime-guard.ts
+++ b/src/infra/runtime-guard.ts
@@ -15,7 +15,7 @@ export function assertSupportedRuntime(): void {
major < MIN_NODE_MAJOR || (major === MIN_NODE_MAJOR && minor < MIN_NODE_MINOR);
if (unsupported) {
throw new Error(
- `IronClaw requires Node ${MIN_NODE_MAJOR}.${MIN_NODE_MINOR}+ (current: ${process.versions.node}).`,
+ `DenchClaw requires Node ${MIN_NODE_MAJOR}.${MIN_NODE_MINOR}+ (current: ${process.versions.node}).`,
);
}
}
diff --git a/src/version.ts b/src/version.ts
index d58b3c45ab6..e2bb7164d21 100644
--- a/src/version.ts
+++ b/src/version.ts
@@ -1,7 +1,7 @@
import { createRequire } from "node:module";
declare const __OPENCLAW_VERSION__: string | undefined;
-const CORE_PACKAGE_NAME = "ironclaw";
+const CORE_PACKAGE_NAME = "denchclaw";
const PACKAGE_JSON_CANDIDATES = [
"../package.json",