From a6a521ec224be1b8c21060a9607cd1f8bcca67a3 Mon Sep 17 00:00:00 2001 From: kumarabhirup Date: Thu, 12 Feb 2026 22:54:57 -0800 Subject: [PATCH] rebrand: use ironclaw as default CLI/package name and bump to 2026.2.10-1.10 - Switch DEFAULT_PACKAGE_NAME to ironclaw in update-cli and update-runner - Add cliName param to system prompt builder for dynamic CLI references - Update README clone URL from openclaw-ai-sdk to ironclaw - Update cron dashboard empty state to reference ironclaw CLI - Restructure dench skill: flatten knowledge/ paths, add browser use section --- README.md | 4 +- .../app/components/cron/cron-dashboard.tsx | 2 +- package.json | 2 +- skills/dench/SKILL.md | 84 +++++++++++-------- src/agents/cli-runner/helpers.ts | 2 + .../pi-embedded-runner/system-prompt.ts | 3 + src/agents/system-prompt.test.ts | 14 +++- src/agents/system-prompt.ts | 24 ++++-- src/cli/update-cli.ts | 19 +++-- src/infra/update-runner.ts | 4 +- 10 files changed, 101 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index b979d00ef12..08c9cd3896d 100644 --- a/README.md +++ b/README.md @@ -40,8 +40,8 @@ ironclaw onboard --install-daemon ### From source ```bash -git clone https://github.com/kumarabhirup/openclaw-ai-sdk.git -cd openclaw-ai-sdk +git clone https://github.com/kumarabhirup/ironclaw.git +cd ironclaw pnpm install pnpm build diff --git a/apps/web/app/components/cron/cron-dashboard.tsx b/apps/web/app/components/cron/cron-dashboard.tsx index 68f28570724..86e39b3be6e 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 openclaw cron add to create one. + No cron jobs configured. Use ironclaw cron add to create one.

) : ( diff --git a/package.json b/package.json index 46f3b9b1a51..47561069a18 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ironclaw", - "version": "2026.2.10-1.9", + "version": "2026.2.10-1.10", "description": "AI-powered CRM platform with multi-channel agent gateway, DuckDB workspace, and knowledge management", "keywords": [], "license": "MIT", diff --git a/skills/dench/SKILL.md b/skills/dench/SKILL.md index 795d6dc8f07..32aff78ea4e 100644 --- a/skills/dench/SKILL.md +++ b/skills/dench/SKILL.md @@ -1,30 +1,31 @@ --- name: dench -description: Manage Dench CRM workspace - objects, fields, entries via DuckDB and documents as markdown files in a nested knowledge tree. +description: Manage Database and everything else in the workspace - objects, fields, entries via DuckDB and documents as markdown files in a nested knowledge tree. Acts as your second brain. metadata: { "openclaw": { "inject": true, "always": true, "emoji": "📊" } } --- -# Dench CRM Workspace +# Dench Workspace -You manage a Dench CRM workspace stored locally at `dench/` in your working directory. -All structured data lives in **DuckDB** (`dench/workspace.duckdb`). Documents are **markdown files** in `dench/knowledge/`. Organization context is in `dench/workspace_context.yaml` (READ-ONLY). +You manage a Dench workspace stored locally at `dench/` in your working directory. +All structured data lives in **DuckDB** (`dench/workspace.duckdb`). Documents are **markdown files** in `dench/**`. Organization context is in `dench/workspace_context.yaml` (READ-ONLY). + +All actions should look into / edit and work on the `dench/**` directory by default unless told otherwise. Exceptions to this are the `SOUL.md`, `skills/`, `memory/`, `USER.md`, `IDENTITY.md`, `TOOLS.md`, `AGENTS.md` and `MEMORY.md` and other such files. ## Workspace Structure ``` dench/ - workspace_context.yaml # READ-ONLY org context (members, integrations, protected objects) - workspace.duckdb # DuckDB database — sole source of truth for structured data - knowledge/ # Nested knowledge tree (sidebar mirrors this) - people/ # Object directory - .object.yaml # Object metadata projection - onboarding-guide.md # Document nested under object - companies/ + workspace_context.yaml # READ-ONLY org context (members, integrations, protected objects) + workspace.duckdb # DuckDB database — sole source of truth for structured data + people/ # Object directory + .object.yaml # Object metadata projection + onboarding-guide.md # Document nested under object + companies/ + .object.yaml + projects/ + projects.md # Document content + tasks/ # Object nested under document .object.yaml - projects/ - projects.md # Document content - tasks/ # Object nested under document - .object.yaml exports/ # On-demand CSV/Parquet exports WORKSPACE.md # Auto-generated schema summary ``` @@ -72,8 +73,8 @@ duckdb dench/workspace.duckdb -json " " # 2. Write .object.yaml from the query results -mkdir -p dench/knowledge/lead -cat > dench/knowledge/lead/.object.yaml << 'YAML' +mkdir -p dench/lead +cat > dench/lead/.object.yaml << 'YAML' id: "AbCdEfGh..." name: "lead" description: "Sales leads tracking" @@ -211,6 +212,8 @@ CREATE TABLE IF NOT EXISTS documents ( INSTALL fts; LOAD fts; ``` +### ALL ID fields must be a nanoid ID. + ## Auto-Generated Views After every object or field mutation, regenerate the PIVOT view for each affected object. Views are stored queries (zero data duplication) that make the EAV pattern invisible: @@ -382,13 +385,13 @@ COMMIT; **Step 2 — Filesystem: Create object directory + .object.yaml** (exec call): ```bash -mkdir -p dench/knowledge/lead +mkdir -p dench/lead # Query the object metadata from DuckDB to build .object.yaml OBJ_ID=$(duckdb dench/workspace.duckdb -noheader -list "SELECT id FROM objects WHERE name = 'lead'") ENTRY_COUNT=$(duckdb dench/workspace.duckdb -noheader -list "SELECT COUNT(*) FROM entries WHERE object_id = '$OBJ_ID'") -cat > dench/knowledge/lead/.object.yaml << 'YAML' +cat > dench/lead/.object.yaml << 'YAML' id: "" name: "lead" description: "Sales leads tracking" @@ -423,7 +426,7 @@ YAML # Verify view works duckdb dench/workspace.duckdb "SELECT COUNT(*) FROM v_lead" # Verify .object.yaml exists -cat dench/knowledge/lead/.object.yaml +cat dench/lead/.object.yaml ``` ## Kanban Boards @@ -473,8 +476,8 @@ COMMIT; **Step 2 — Filesystem (MANDATORY):** ```bash -mkdir -p dench/knowledge/task -cat > dench/knowledge/task/.object.yaml << 'YAML' +mkdir -p dench/task +cat > dench/task/.object.yaml << 'YAML' id: "" name: "task" description: "Task tracking board" @@ -490,7 +493,7 @@ fields: YAML ``` -**Step 3 — Verify:** `duckdb dench/workspace.duckdb "SELECT COUNT(*) FROM v_task"` and `cat dench/knowledge/task/.object.yaml`. +**Step 3 — Verify:** `duckdb dench/workspace.duckdb "SELECT COUNT(*) FROM v_task"` and `cat dench/task/.object.yaml`. ## Field Types Reference @@ -552,11 +555,11 @@ YAML ## Document Management -Documents are markdown files in `dench/knowledge/`. The DuckDB `documents` table tracks metadata only; the `.md` file IS the content. +Documents are markdown files in `dench/**`. The DuckDB `documents` table tracks metadata only; the `.md` file IS the content. ### Create Document -1. Write the `.md` file: `write dench/knowledge/projects/roadmap.md` +1. Write the `.md` file: `write dench/projects/roadmap.md` 2. Insert metadata into DuckDB: ```sql @@ -590,8 +593,8 @@ You MUST complete ALL steps below after ANY schema mutation (create/update/delet ### After creating or modifying an OBJECT or its FIELDS: - [ ] `CREATE OR REPLACE VIEW v_{object_name}` — regenerate the PIVOT view -- [ ] `mkdir -p dench/knowledge/{object_name}/` — create the object directory -- [ ] Write `dench/knowledge/{object_name}/.object.yaml` — metadata projection with id, name, description, icon, default_view, entry_count, and full field list +- [ ] `mkdir -p dench/{object_name}/` — create the object directory +- [ ] Write `dench/{object_name}/.object.yaml` — metadata projection with id, name, description, icon, default_view, entry_count, and full field list - [ ] If object has a `parent_document_id`, place directory inside the parent document's directory - [ ] Update `WORKSPACE.md` if it exists @@ -603,12 +606,12 @@ You MUST complete ALL steps below after ANY schema mutation (create/update/delet ### After deleting an OBJECT: - [ ] `DROP VIEW IF EXISTS v_{object_name}` — remove the view -- [ ] `rm -rf dench/knowledge/{object_name}/` — remove the directory (unless it contains nested documents that need relocating) +- [ ] `rm -rf dench/{object_name}/` — remove the directory (unless it contains nested documents that need relocating) - [ ] Update `WORKSPACE.md` ### After creating or modifying a DOCUMENT: -- [ ] Write the `.md` file to the correct path in `dench/knowledge/` +- [ ] Write the `.md` file to the correct path in `dench/**` - [ ] `INSERT INTO documents` — ensure metadata row exists with correct `file_path`, `parent_id`, or `parent_object_id` These steps ensure the filesystem always mirrors DuckDB. The sidebar depends on `.object.yaml` files — if they are missing, objects will not appear. @@ -619,7 +622,7 @@ Reports are JSON config files (`.report.json`) that the web app renders as live ### Report file format -Store reports as `.report.json` files in `dench/reports/` (create the directory if needed). The JSON schema: +Store reports as `.report.json` files in `dench/**` (wherever appropriate / create directories if you need for better structure). The JSON schema: ```json { @@ -763,9 +766,9 @@ The user can then "Pin" the inline report to save it as a `.report.json` file. After creating a `.report.json` file: - [ ] Verify the report JSON is valid and all SQL queries work: test each panel's SQL individually -- [ ] Ensure `dench/reports/` directory exists -- [ ] Write the file: `dench/reports/{slug}.report.json` -- [ ] Tell the user they can view it in the workspace sidebar under "Reports" +- [ ] Choose which directory the report should be created in the `dench/` workspace based on the context of the conversation, if nothing vert relevant, create/use the `dench/reports/` directory. +- [ ] Write the file: `dench/**/{slug}.report.json` +- [ ] Tell the user they can view it in the workspace sidebar under whichever directory it was rightfully placed in based on the context. ### Choosing the right chart type @@ -780,7 +783,7 @@ After creating a `.report.json` file: ## Critical Reminders - Handle the ENTIRE CRM operation from analysis to SQL execution to filesystem projection to summary -- **NEVER SKIP FILESYSTEM PROJECTION**: After creating/modifying any object, you MUST create/update `dench/knowledge/{object}/.object.yaml` AND the `v_{object}` view. If you skip this, the object will be invisible in the sidebar. This is NOT optional. +- **NEVER SKIP FILESYSTEM PROJECTION**: After creating/modifying any object, you MUST create/update `dench/{object}/.object.yaml` AND the `v_{object}` view. If you skip this, the object will be invisible in the sidebar. This is NOT optional. - **THREE STEPS, EVERY TIME**: (1) SQL transaction, (2) filesystem projection (.object.yaml + directory), (3) verify. An operation is NOT complete until all three are done. - Always check existing data before creating (`SELECT` before `INSERT`, or `ON CONFLICT`) - Use views (`v_{object}`) for all reads — never write raw PIVOT queries for search @@ -798,3 +801,16 @@ After creating a `.report.json` file: - **workspace_context.yaml**: READ-ONLY. Never modify. Data flows from Dench UI only. - **Source of truth**: DuckDB for all structured data. Filesystem for document content and navigation tree. Never duplicate entry data to the filesystem. - **ENTRY COUNT**: After adding entries, update `entry_count` in `.object.yaml`. +- **NEVER POLLUTE THE WORKSPACE**: Always keep cleaning / organising the workspace to something more nicely structured. Always look out for bloat and too many random files scattered around everywhere for no reason, every time you do any actions in filesystem always try to come up with the most efficient and nice file system structure for inside the `dench/` workspace. +- **TEMPORARY FILES**: All temporary scripts / code / text / other files as and when needed for processing must go into `dench/tmp/` directory (create it if it doesn't exist, only if needed). + +## Browser Use + +Many times, when asked to do complex tasks and if you don't have an API or a real way to do it locally, always spin up your own Chromium browser instead of relying on the user to install the OpenClaw Relay extension (use the extension only if explicitly asked to, else, just don't)! + +### Steps to start and use your own browser + +- **DETERMINE IF YOUR INTERNAL CHROMIUM BROWSER PROFILE IS FRESH AND EMPTY**: Proceed to the next step only if your internal browser profile is empty and fresh. Else discard, and just use open the new Chromium Browser window and use it like usual. +- **FIND THE USER'S DEFAULT CHROME PROFILE**: Most users have their main active chrome profile that they actively use with all the auth state, cookies, passwords, addresses, history, cache, etc. It can be on Chrome, Edge, Brave or any other Chromium browser they mostly use. Determine which one on the computer is the most active and current one. +- DISCARD NEXT STEPS IF YOU CAN'T FIND THEIR CURRENT AND ACTIVE CHROME PROFILE. +- **COPY THAT USER'S DEFAULT CHROME PROFILE, INTO YOUR OWN CHROME PROFILE**: Once you find their Chrome profile, copy all its content and replace your own internal Chromium Browser's Profile with that one, so now you can have all the same access as the user does on their main chrome profile. diff --git a/src/agents/cli-runner/helpers.ts b/src/agents/cli-runner/helpers.ts index 3674d8f2ed9..96d4675e740 100644 --- a/src/agents/cli-runner/helpers.ts +++ b/src/agents/cli-runner/helpers.ts @@ -8,6 +8,7 @@ import type { ThinkLevel } from "../../auto-reply/thinking.js"; import type { OpenClawConfig } from "../../config/config.js"; import type { CliBackendConfig } from "../../config/types.js"; import type { EmbeddedContextFile } from "../pi-embedded-helpers.js"; +import { resolveCliName } from "../../cli/cli-name.js"; import { runExec } from "../../process/exec.js"; import { buildTtsSystemPromptHint } from "../../tts/tts.js"; import { escapeRegExp, isRecord } from "../../utils.js"; @@ -245,6 +246,7 @@ export function buildSystemPrompt(params: { contextFiles: params.contextFiles, ttsHint, memoryCitationsMode: params.config?.memory?.citations, + cliName: resolveCliName(), }); } diff --git a/src/agents/pi-embedded-runner/system-prompt.ts b/src/agents/pi-embedded-runner/system-prompt.ts index bc040f5e3c4..ffb4d82ae2e 100644 --- a/src/agents/pi-embedded-runner/system-prompt.ts +++ b/src/agents/pi-embedded-runner/system-prompt.ts @@ -48,6 +48,8 @@ export function buildEmbeddedSystemPrompt(params: { userTimeFormat?: ResolvedTimeFormat; contextFiles?: EmbeddedContextFile[]; memoryCitationsMode?: MemoryCitationsMode; + /** CLI binary name (e.g. "ironclaw" or "openclaw"). Passed through to buildAgentSystemPrompt. */ + cliName?: string; }): string { return buildAgentSystemPrompt({ workspaceDir: params.workspaceDir, @@ -74,6 +76,7 @@ export function buildEmbeddedSystemPrompt(params: { userTimeFormat: params.userTimeFormat, contextFiles: params.contextFiles, memoryCitationsMode: params.memoryCitationsMode, + cliName: params.cliName, }); } diff --git a/src/agents/system-prompt.test.ts b/src/agents/system-prompt.test.ts index 7b2d9718832..191695cd52b 100644 --- a/src/agents/system-prompt.test.ts +++ b/src/agents/system-prompt.test.ts @@ -93,16 +93,26 @@ describe("buildAgentSystemPrompt", () => { expect(prompt).toContain("..."); }); - it("includes a CLI quick reference section", () => { + it("includes a CLI quick reference section with default CLI name", () => { const prompt = buildAgentSystemPrompt({ workspaceDir: "/tmp/openclaw", }); expect(prompt).toContain("## OpenClaw CLI Quick Reference"); - expect(prompt).toContain("openclaw gateway restart"); + expect(prompt).toContain("ironclaw gateway restart"); expect(prompt).toContain("Do not invent commands"); }); + it("uses custom cliName in CLI quick reference when provided", () => { + const prompt = buildAgentSystemPrompt({ + workspaceDir: "/tmp/openclaw", + cliName: "openclaw", + }); + + expect(prompt).toContain("openclaw gateway restart"); + expect(prompt).not.toContain("ironclaw gateway"); + }); + it("lists available tools when provided", () => { const prompt = buildAgentSystemPrompt({ workspaceDir: "/tmp/openclaw", diff --git a/src/agents/system-prompt.ts b/src/agents/system-prompt.ts index 36ab37060ec..e21f05c5e68 100644 --- a/src/agents/system-prompt.ts +++ b/src/agents/system-prompt.ts @@ -3,6 +3,7 @@ import type { MemoryCitationsMode } from "../config/types.memory.js"; import type { ResolvedTimeFormat } from "./date-time.js"; import type { EmbeddedContextFile } from "./pi-embedded-helpers.js"; import { SILENT_REPLY_TOKEN } from "../auto-reply/tokens.js"; +import { DEFAULT_CLI_NAME } from "../cli/cli-name.js"; import { listDeliverableMessageChannels } from "../utils/message-channel.js"; /** @@ -143,7 +144,12 @@ function buildVoiceSection(params: { isMinimal: boolean; ttsHint?: string }) { return ["## Voice (TTS)", hint, ""]; } -function buildDocsSection(params: { docsPath?: string; isMinimal: boolean; readToolName: string }) { +function buildDocsSection(params: { + docsPath?: string; + isMinimal: boolean; + readToolName: string; + cliName: string; +}) { const docsPath = params.docsPath?.trim(); if (!docsPath || params.isMinimal) { return []; @@ -156,7 +162,7 @@ function buildDocsSection(params: { docsPath?: string; isMinimal: boolean; readT "Community: https://discord.com/invite/clawd", "Find new skills: https://clawhub.com", "For OpenClaw behavior, commands, config, or architecture: consult local docs first.", - "When diagnosing issues, run `openclaw status` yourself when possible; only ask the user if you lack access (e.g., sandboxed).", + `When diagnosing issues, run \`${params.cliName} status\` yourself when possible; only ask the user if you lack access (e.g., sandboxed).`, "", ]; } @@ -215,7 +221,10 @@ export function buildAgentSystemPrompt(params: { channel: string; }; memoryCitationsMode?: MemoryCitationsMode; + /** CLI binary name (e.g. "ironclaw" or "openclaw"). Defaults to DEFAULT_CLI_NAME. */ + cliName?: string; }) { + const cli = params.cliName?.trim() || DEFAULT_CLI_NAME; const coreToolSummaries: Record = { read: "Read file contents", write: "Create or overwrite files", @@ -369,6 +378,7 @@ export function buildAgentSystemPrompt(params: { docsPath: params.docsPath, isMinimal, readToolName, + cliName: cli, }); const workspaceNotes = (params.workspaceNotes ?? []).map((note) => note.trim()).filter(Boolean); @@ -415,11 +425,11 @@ export function buildAgentSystemPrompt(params: { "## OpenClaw CLI Quick Reference", "OpenClaw is controlled via subcommands. Do not invent commands.", "To manage the Gateway daemon service (start/stop/restart):", - "- openclaw gateway status", - "- openclaw gateway start", - "- openclaw gateway stop", - "- openclaw gateway restart", - "If unsure, ask the user to run `openclaw help` (or `openclaw gateway --help`) and paste the output.", + `- ${cli} gateway status`, + `- ${cli} gateway start`, + `- ${cli} gateway stop`, + `- ${cli} gateway restart`, + `If unsure, ask the user to run \`${cli} help\` (or \`${cli} gateway --help\`) and paste the output.`, "", ...skillsSection, ...memorySection, diff --git a/src/cli/update-cli.ts b/src/cli/update-cli.ts index 799ed32aa12..bfcf0634e20 100644 --- a/src/cli/update-cli.ts +++ b/src/cli/update-cli.ts @@ -125,8 +125,8 @@ const UPDATE_QUIPS = [ ]; const MAX_LOG_CHARS = 8000; -const DEFAULT_PACKAGE_NAME = "openclaw"; -const CORE_PACKAGE_NAMES = new Set([DEFAULT_PACKAGE_NAME, "ironclaw"]); +const DEFAULT_PACKAGE_NAME = "ironclaw"; +const CORE_PACKAGE_NAMES = new Set([DEFAULT_PACKAGE_NAME, "openclaw"]); const CLI_NAME = resolveCliName(); const OPENCLAW_REPO_URL = "https://github.com/openclaw/openclaw.git"; @@ -1104,7 +1104,7 @@ export async function updateCommand(opts: UpdateCommandOptions): Promise { export async function updateWizardCommand(opts: UpdateWizardOptions = {}): Promise { if (!process.stdin.isTTY) { defaultRuntime.error( - "Update wizard requires a TTY. Use `openclaw update --channel ` instead.", + `Update wizard requires a TTY. Use \`${CLI_NAME} update --channel \` instead.`, ); defaultRuntime.exit(1); return; @@ -1260,7 +1260,10 @@ export function registerUpdateCli(program: Command) { ["openclaw --update", "Shorthand for openclaw update"], ] as const; const fmtExamples = examples - .map(([cmd, desc]) => ` ${theme.command(cmd)} ${theme.muted(`# ${desc}`)}`) + .map( + ([cmd, desc]) => + ` ${theme.command(replaceCliName(cmd, CLI_NAME))} ${theme.muted(`# ${desc}`)}`, + ) .join("\n"); return ` ${theme.heading("What this does:")} @@ -1269,7 +1272,7 @@ ${theme.heading("What this does:")} ${theme.heading("Switch channels:")} - Use --channel stable|beta|dev to persist the update channel in config - - Run openclaw update status to see the active channel and source + - Run ${CLI_NAME} update status to see the active channel and source - Use --tag for a one-off npm update without persisting ${theme.heading("Non-interactive:")} @@ -1331,9 +1334,9 @@ ${theme.muted("Docs:")} ${formatDocsLink("/cli/update", "docs.openclaw.ai/cli/up "after", () => `\n${theme.heading("Examples:")}\n${formatHelpExamples([ - ["openclaw update status", "Show channel + version status."], - ["openclaw update status --json", "JSON output."], - ["openclaw update status --timeout 10", "Custom timeout."], + [`${CLI_NAME} update status`, "Show channel + version status."], + [`${CLI_NAME} update status --json`, "JSON output."], + [`${CLI_NAME} update status --timeout 10`, "Custom timeout."], ])}\n\n${theme.heading("Notes:")}\n${theme.muted( "- Shows current update channel (stable/beta/dev) and source", )}\n${theme.muted("- Includes git tag/branch/SHA for source checkouts")}\n\n${theme.muted( diff --git a/src/infra/update-runner.ts b/src/infra/update-runner.ts index 4790a306a9f..c4bdba497f7 100644 --- a/src/infra/update-runner.ts +++ b/src/infra/update-runner.ts @@ -80,8 +80,8 @@ const DEFAULT_TIMEOUT_MS = 20 * 60_000; const MAX_LOG_CHARS = 8000; const PREFLIGHT_MAX_COMMITS = 10; const START_DIRS = ["cwd", "argv1", "process"]; -const DEFAULT_PACKAGE_NAME = "openclaw"; -const CORE_PACKAGE_NAMES = new Set([DEFAULT_PACKAGE_NAME, "ironclaw"]); +const DEFAULT_PACKAGE_NAME = "ironclaw"; +const CORE_PACKAGE_NAMES = new Set([DEFAULT_PACKAGE_NAME, "openclaw"]); function normalizeDir(value?: string | null) { if (!value) {