Phase 0 reference audit · forgeapps monorepo + ForgeBot · generated 2026-06-26
ForgeBot already runs on Hermes. On this Mac (forgebot-mini) OpenClaw is not installed and no gateway runs on it; Hermes is the live harness and already self-prunes OpenClaw residue. The hard runtime cutover is done.
What remains is decoupling the repo's naming, paths and conventions from OpenClaw (Scope A) plus, for a literal 100%, migrating AdamoBot's runtime off OpenClaw on its own Windows host (Scope B).
Each file is bucketed once by migration disposition. live-functional is the real work; historical-log is left untouched.
| Bucket | Files | Lines | Disposition |
|---|---|---|---|
historical-log | 272 | 1887 | Run-logs / archives / memory — never rewrite (Documentation principle). Excluded from the worklist. |
persona-source | 71 | 296 | .openclaw/workspace/ identity + config tree — Phase 1 move target (live persona files + memory). |
path-config | 211 | 2197 | Config/manifest files and ~/.openclaw path constants — Phase 2 (re-test Slack media after). |
adamobot-only | 138 | 972 | AdamoBot / clawdbot surface — keep working until Scope B (AdamoBot runtime migration). |
live-functional | 74 | 208 | Live ForgeBot code, skills, and routines — the primary Scope A worklist. |
other-doc | 184 | 663 | Remaining prose mentions — triage case-by-case. |
The actual ForgeBot code, skills, and routine scripts coupled to OpenClaw. Expand any file to see its matching lines. Highest-value targets: the forgebotmini-maintenance routine (ForgeBot's own host) and the dashboard gateway-origin pages.
**Default to `profile="openclaw"`**. It is always running on port 18800. No extension needed.browser action=navigate profile=openclaw targetUrl=https://example.combrowser action=screenshot profile=openclawbrowser action=screenshot profile=openclaw targetUrl=https://example.com| `openclaw` | 18800 | No logins (isolated browser) | **DEFAULT.** Public pages, production verification, any URL that doesn't need auth |1. **Navigate** to the URL with `browser` tool, `profile="openclaw"`| "Extension not connected" | You're using `profile="chrome"`. Switch to `profile="openclaw"`. || openclaw browser not running | `browser action=start profile=openclaw` |The `openclaw` browser has no logins. For authenticated pages:- **NEVER** default to `profile="chrome"` use `openclaw` first.browser action=act profile=openclaw request={"kind":"resize","width":1920,"height":1080}browser action=navigate profile=openclaw targetUrl=https://jd.forgefx.dev/demos/forgeview-XXX-rNN/browser action=screenshot profile=openclawbrowser action=act profile=openclaw request={"kind":"resize","width":1920,"height":1080}browser action=navigate profile=openclaw targetUrl=https://jd.forgefx.dev/demos/forgeview-XXX-rNN/browser action=screenshot profile=openclaw- openclaw browser (port 18800) is always running. This is the golden path.If the openclaw browser needs gateway auth (e.g. "unauthorized: gateway token missing"):2. Open: `browser action=navigate profile=openclaw targetUrl=http://127.0.0.1:18789/overview`- 2026-02-16: Complete rewrite. Three methods documented. openclaw browser as default. Auth strategy. General-purpose, not just ForgeView.probeOpenclaw,openclaw: { status: 'degraded', failing: ['slack'], uptime_ms: 1234, log_age_min: 12.3 },openclawModel: { model: 'claude-cli/sonnet', alias: 'sonnet', fallbacks: ['fallback'] },assert.equal(payload.openclaw_status, 'degraded');const older = join(dir, 'openclaw-2026-06-02.log');const newer = join(dir, 'openclaw-2026-06-03.log');assert.match(resolveGatewayLog(join(dir, 'does-not-exist')), /\.openclaw[/\\]logs[/\\]gateway\.log$/);test('probeOpenclaw: connection-refused /ready with a FRESH live log reads degraded (restarting), not offline', async () => {const logPath = join(dir, 'openclaw-2026-06-04.log');const result = await probeOpenclaw({ baseUrl: 'http://127.0.0.1:18789', logPath, nowMs });test('probeOpenclaw: connection-refused /ready with a STALE or missing live log stays offline', async () => {const logPath = join(dir, 'openclaw-2026-06-04.log');const stale = await probeOpenclaw({ baseUrl: 'http://127.0.0.1:18789', logPath, nowMs });const missing = await probeOpenclaw({ baseUrl: 'http://127.0.0.1:18789', logPath: join(dir, 'gone.log'), nowMs });* True if a process command is the OpenClaw gateway daemon* (`node .../openclaw/dist/index.js gateway --port …`) — the parent of every* `claude -p … --allowedTools mcp__openclaw__*` brain turn. The brain turn's* OWN argv carries `mcp__openclaw__*` but never the `gateway` token, so thisreturn cmd.includes('openclaw') && cmd.includes('gateway');// The OpenClaw gateway daemon (`node .../openclaw/dist/index.js gateway --port …`)// spawns a fresh `claude -p … --allowedTools mcp__openclaw__*` brain turn for each// in-flight reply. Matched on the gateway ancestor's command (`openclaw` +// `gateway`), which a brain turn's own `mcp__openclaw__*` argv never carries.return 'OpenClaw gateway (brain turn)';// Gateway brain turns (origin "OpenClaw gateway (brain turn)") are never(session) => !session.is_current && !session.origin.startsWith('OpenClaw gateway'),* True if a process command is the OpenClaw gateway daemon* (`node .../openclaw/dist/index.js gateway --port …`) — the parent of every* `claude -p … --allowedTools mcp__openclaw__*` brain turn. The brain turn's* OWN argv carries `mcp__openclaw__*` but never the `gateway` token, so thisreturn cmd.includes('openclaw') && cmd.includes('gateway');// The OpenClaw gateway daemon (`node .../openclaw/dist/index.js gateway --port …`)// spawns a fresh `claude -p … --allowedTools mcp__openclaw__*` brain turn for each// in-flight reply. Matched on the gateway ancestor's command (`openclaw` +// `gateway`), which a brain turn's own `mcp__openclaw__*` argv never carries.return 'OpenClaw gateway (brain turn)';// Gateway brain turns (origin "OpenClaw gateway (brain turn)") are never(session) => !session.is_current && !session.origin.startsWith('OpenClaw gateway'),const oldest = path.join(d, 'openclaw-2026-05-31.log');const older = path.join(d, 'openclaw-2026-06-01.log');const newer = path.join(d, 'openclaw-2026-06-02.log');const files = discoverLogFiles(path.join(d, 'openclaw-*.log'), ['/nonexistent-a', '/nonexistent-b']);assert.equal(path.basename(files[0]), 'openclaw-2026-06-02.log');assert.equal(path.basename(files[1]), 'openclaw-2026-06-01.log');const only = path.join(d, 'openclaw-2026-06-02.log');const files = discoverLogFiles(path.join(d, 'openclaw-*.log'), ['/nonexistent-a', '/nonexistent-b']);assert.deepEqual(files.map((p) => path.basename(p)), ['openclaw-2026-06-02.log']);const files = discoverLogFiles(path.join(d, 'openclaw-*.log'), [legacyLog, path.join(d, 'gateway.err.log')]);slack_equivalent: "Slack-equivalent OpenClaw path",source: runtimeMode === "slack_equivalent" ? "openclaw_chat_completions" : "openrouter_chat_completions",setApiError("Slack-equivalent runtime needs a Test or Production OpenClaw URL on the selected agent. Add it from Agents, then run again.");model: runtimeMode === "slack_equivalent" ? "slack_equivalent_openclaw" : selectedModel,Choose whether this run is a direct model benchmark or the Slackbot/OpenClaw path users hit in Slack.<SelectItem value="slack_equivalent">Slack-equivalent OpenClaw path</SelectItem>{slackEndpointStatus.configured ? "OpenClaw URL configured" : "OpenClaw URL missing"}Evaluation items will be sent through the selected agent's OpenClaw URL using a ForgeBench session key, then scored from the returned bot answer.Add a Test OpenClaw URL on the selected agent before running Slack-equivalent evaluations.* 3. it does NOT descend from the OpenClaw gateway daemon (a brain turn carries* `--allowedTools mcp__openclaw__*`, so guards 1+2 alone would match it —* True if `pid` descends from an OpenClaw gateway daemon — i.e. it is a live* turn's own argv carries `--allowedTools mcp__openclaw__*` — which looks* routine's hard READ-ONLY-on-the-gateway rule. forgebot-mini runs no OpenClaw* 3. it does NOT descend from the OpenClaw gateway daemon (never reap a live# Open clawd browser once, reuse for all buildsbrowser action=open profile=clawd targetUrl=https://jd.forgefx.dev/demos/forgeview-001/browser action=navigate profile=clawd targetId=<ID> targetUrl=https://jd.forgefx.dev/demos/forgeview-XXX-rNN/browser action=screenshot profile=openclaw targetId=<ID> # See screenshot skill: .claude/skills/dev/subskills/screenshot/SUBSKILL.mdbrowser action=console profile=clawd targetId=<ID> level=error# Open clawd browser once, reuse for all buildsbrowser action=open profile=clawd targetUrl=https://jd.forgefx.dev/demos/forgeview-001/browser action=navigate profile=clawd targetId=<ID> targetUrl=https://jd.forgefx.dev/demos/forgeview-XXX-rNN/browser action=screenshot profile=openclaw targetId=<ID> # See screenshot skill: .claude/skills/dev/subskills/screenshot/SUBSKILL.mdbrowser action=console profile=clawd targetId=<ID> level=error* 3. it does NOT descend from the OpenClaw gateway daemon (a brain turn carries* `--allowedTools mcp__openclaw__*`, so guards 1+2 alone would match it —* True if `pid` descends from an OpenClaw gateway daemon — i.e. it is a live* turn's own argv carries `--allowedTools mcp__openclaw__*` — which looks* 3. it does NOT descend from the OpenClaw gateway daemon (never reap a livedescription: Connect to Adam's live Chrome session via Chrome DevTools Protocol (CDP). Use as a fallback when OpenClaw Browser Relay won't work — e.g., sites that block headless browsers (LinkedIn, Salesforce native), cross-origin iframes (## When to Use This vs. OpenClaw Browser Relay| General web automation (public pages) | OpenClaw `browser` tool (default) || Chrome extension relay attached | OpenClaw `browser` tool (profile=chrome) |{ name: 'SOUL.md', path: 'C:\\Users\\AdamK\\clawd\\SOUL.md' },{ name: 'AGENTS.md', path: 'C:\\Users\\AdamK\\clawd\\AGENTS.md' },{ name: 'HEARTBEAT.md', path: 'C:\\Users\\AdamK\\clawd\\HEARTBEAT.md' },{ name: 'USER.md', path: 'C:\\Users\\AdamK\\clawd\\USER.md' },'OpenClaw\'s sentinel for "do not reply in Slack." The entire text output must be exactly NO_REPLY and nothing else; any surrounding prose ("I should not reply. NO_REPLY") gets posted to the channel verbatim.','Not in the OpenClaw schema — enforced behaviorally. Being in a thread where AdamoBot previously spoke is NOT permission to keep talking. Each follow-up needs a new explicit mention with an explicit response request.',seeAlso: ['Rule Zero', 'OpenClaw'],term: 'OpenClaw',<div className="border-l-2 border-red-500 pl-3"><strong className="text-red-400">🔥 AGGRESSIVE SELF-IMPROVEMENT OBJECTIVES</strong><ul className="mt-1 space-y-1 list-disc list-inside"><li><strong>Velocity:</strong> Target 6 builds/hr. Curre<div className="border-l-2 border-blue-500 pl-3"><strong className="text-blue-400">⏰ 5-MINUTE VELOCITY CHECK (Cron Rules)</strong><pre className="mt-1 bg-black/30 p-2 rounded overflow-x-auto text-[10px]">{`1. Run: doppler run -- python claw<div><strong className="text-foreground">📁 Key Files (Read These First)</strong><ul className="mt-1 space-y-1 list-disc list-inside"><li><code>clawd/memory/forgeview-philosophy.md</code> - <strong>START HERE</strong> — mission, principles,<div><strong className="text-foreground">🔍 Quick Status Check</strong><pre className="mt-1 bg-black/30 p-2 rounded overflow-x-auto text-[10px]">{`# What's the current state?\nbrowser action=open profile=clawd targetUrl=https://jd.forgefx.d- `openclaw` - scan the `memory/` folder in the project root (daily logs + MEMORY.md)# openclaw# openclaw - also list daily logsbrowser action=act profile=openclaw request={"kind":"resize","width":1920,"height":1080}browser action=navigate profile=openclaw targetUrl=https://jd.forgefx.dev/demos/forgeview-XXX/?v=rNNbrowser action=screenshot profile=openclaw<span className="text-primary">CLAWD</span><span className="text-sm text-muted-foreground">OpenClaw Gateway Health</span>table. Events logged by OpenClaw gateway watchdog.<Label htmlFor="test_webhook_url">Test OpenClaw URL</Label><Label htmlFor="production_webhook_url">Production OpenClaw URL</Label>placeholder="Optional production Slackbot/OpenClaw endpoint"# 7) OpenClaw browser HTTP/code/GPU/service-worker caches — NOT cookies/loginBR="$HOME/.openclaw/browser/openclaw/user-data"&& add "openclaw-browser-caches"16. **Doppler-policy-violation scan (added 2026-05-14 Run #33, codifies LEARNINGS rule 33; extended 2026-05-15 Run #42 with hardcoded-secret-literal sub-scan + investigation-result codification per LEARNINGS rule 41).** Every run, sweep the- **Unbounded-grep rule (added 2026-05-15 Run #43, codifies LEARNINGS rule 43).** Once the first hit appears via the path-bounded detector above, the routine MUST run `git grep -l "<literal>"` with NO path bound to enumerate every appearanc| `.openclaw/` | dir | OpenClaw workspace. |# 7) OpenClaw browser HTTP/code/GPU/service-worker caches — NOT cookies/loginBR="$HOME/.openclaw/browser/openclaw/user-data"&& add "openclaw-browser-caches"'Run under doppler or place a Doppler service token at .openclaw/.doppler-token.',if (existsSync(path.join(current, '.openclaw'))) {const tokenFile = path.join(repo, '.openclaw', '.doppler-token');# Use browser tool: profile=openclaw, targetUrl=http://localhost:4115# Note: requires browser.ssrfPolicy.allowPrivateNetwork: true in openclaw.json- Added Slack ack reaction policy document and disabled ack in openclaw config.- Set heartbeat interval change and verified openclaw deployment paths.## Migration Notes: .openclaw -> forgeapps (2026-02-26)- **Old repo:** `adamkane/.openclaw` apps at `forgeapps/apps/<name>/`description: Credential repair service for Claude Code, AdamoBot, and OpenClaw. The one place all scheduled tasks and skills call when authentication fails. Diagnoses Doppler, API tokens, and service credentials across Windows/Mac/VM enviroCredential repair service for Claude Code, AdamoBot, and OpenClaw. When a scheduled task, skill, or automation hits a credential failure, it calls medic instead of handling it alone.# Supports: native (Claude Code auto-memory), openclaw, project-rootopenclaw|project-root)This template is the most accurate and complete feature list we have. NEVER hand-build a feature list or reuse an old worksheet from `.openclaw/tmp/`. Always download a fresh copy of THIS template and fill it out per request.1. **Copy the template.** Download `Scope_Shakedown_Template_Worksheet.xlsx` from the SharePoint link above (use the `sharepoint-skill` connector). Save the working copy under `.openclaw/tmp/scope-shakedown/`. If the download fails, stop ansed -E 's#(href|src)="/#\1="https://design.forgefx.dev/#g' page.html > .openclaw/tmp/page.htmlnpx tsx .claude/skills/share-preview/scripts/share-preview.ts .openclaw/tmp/page.html --clean page-name| `browser` tool (openclaw profile) | Works for basic pages, untested for WebGL interaction sequences || Simple web page via browser tool | `screenshot` skill → `browser` tool with `profile="openclaw"` |{ path: '/clawd', title: 'Clawd' },<Route path="/clawd" element={<ClawdPage />} /><a href="https://github.com/adamkane/.openclaw/blob/main/repos/appworks/apps/jd/FORGEVIEW-INDEX.md" target="_blank" rel="noopener noreferrer" className="block mb-6 p-4 rounded-lg border-2 border-amber-500/60 bg-amber-500/10 hover:bg-amber-5<div className="p-4 border-b border-border"><div className="flex items-center justify-between"><div><h2 className="text-xl font-semibold text-foreground">✅ Challenge Completion Checklist</h2><p className="text-sm text-muted-foreground mt-1"<p>The agent or process that executed this run. <code className="text-foreground/70">{run.runner}</code> is the OpenClaw heartbeat system, which runs on a recurring schedule and triages ultra-priority issues automatically.</p><p>The OpenClaw session type that triggered this run. <code>heartbeat</code> means it was an automated periodic check, not a manual invocation.</p>const SOURCE = 'openclaw-watchdog';return env.BUSYLIGHT_HEALTH_DIR || path.join(home, '.openclaw', 'busylight-health');# OpenClaw sessions carry --mcp-config .../openclaw-cli-mcp/...; genuinelyif (cli_cmd[i] ~ /openclaw-cli-mcp/) tag = "openclaw";| Jira | Atlassian MCP (`searchJiraIssuesUsingJql`) | Three JQLs per fire: (a) Ultras snapshot — `project = AK AND priority = "Ultra" AND status != Done`; (b) per-fire delta probe — `project = AK AND updated >= -4h AND (labels IS EMPTY **AdamoBot-bot operational Slack signal class (codified 2026-05-25 12:39 HST after 6+ consecutive fires re-discovered the boundary).** Messages where the ForgeFX team interacts directly with AdamoBot in Slack — auth/budget failures ("Openif (parts[0] === ".openclaw") {return `OpenClaw workspace context for \`${relDir}\`, including nearby workspace materials and operator notes.`;# OpenClaw sessions carry --mcp-config .../openclaw-cli-mcp/...; genuinelyif (cli_cmd[i] ~ /openclaw-cli-mcp/) tag = "openclaw";- **Legacy-dir-write drift.** A dir on disk whose name ends in the old `-maintainer/` suffix (e.g. `openclaw-maintainer/`, `forgebooks-maintainer/`) and contains only artifact files (LOGS/REPORT/ERRORS/DASHBOARD/etc, no `ROUTINE.md` of its 9b. **Sync Supabase `routines_catalog`.** `doppler run --project forgeapps --config prd -- pnpm exec tsx crons/routines/routines-maintenance/sync-routines-catalog.ts` — guarantees every routine on disk has a row in `public.routines_catalog`GW=$(openclaw gateway status 2>&1)echo "$GW" | grep -qiE "state active|running" && check "OpenClaw gateway" 1 "" || check "OpenClaw gateway" 0 "run: openclaw gateway start"- Subtree file counts. Always sample: `forgeapps/node_modules`, `forgeapps/apps`, `forgeapps/.git`, `forgeapps/.claude`, `forgeapps/.openclaw`, **and `Documents/worktrees/`**. Git worktrees can appear at `Documents/worktrees/forgeapps/<namep(`2. **Audit archive paths** (${archived.length} files, ${fmtSize(archivedBytes)}). Destinations by file type: ${breakdown}. Archive content rarely belongs in Git LFS route media to ForgeMedia, documents to SharePoint, per \`.openclaw/wor6. Start with the biggest durable operator surfaces first: `.claude/`, `crons/`, `docs/`, `.openclaw/`, then the largest app trees.- **[OB1 / Open Brain](https://github.com/NateBJones-Projects/OB1/blob/main/README.md)** by Nate B. Jones — open-source second-brain pattern that's architecturally adjacent to forgebase: one Supabase database (Postgres + pgvector), one AI g- Mock-up response docs for both proposals (AI-STRAWMAN-DRAFT DOCXs, 2026-06-12) built via `.openclaw/tmp/build_michelle_response.py` and `build_michelle_eri_response.py` in the OpenClaw workspace.- **Browser tool:** Playwright exclusively. Never Chrome DevTools MCP, Claude-in-Chrome, or openclaw browser.* runtime-list.ts - List all SKILL.md files visible to OpenClaw at runtime.ForgeBot runs on **Hermes Agent** (NOT OpenClaw — that skill is stale for this host).SKILL_PATH="/c/Users/AdamK/.openclaw/.claude/skills/testing/browserless/SKILL.md"2. CIC / OpenClaw browser automation| 4th | `browser` tool (openclaw profile) | Only if Playwright is broken or unavailable |SKILL_PATH="/c/Users/AdamK/.openclaw/.claude/skills/testing/stagehand/SKILL.md"const WS = path.join(REPO, '.openclaw', 'workspace')'3. usedByApp: which apps/<x>/ (or "none" if it lives in .claude/, .openclaw/, crons/, outputs/ — archival, not app-served).',{ to: '/clawd', label: 'Clawd' },const apiUrl = `https://api.github.com/repos/adamkane/.openclaw/contents/workspace/docs/${encodeURIComponent(f)}`;{ name: 'OpenClaw', category: 'Other', lowCost: 0, highCost: 50, status: 'keep', keys: 1, managedBy: 'Adam' },source.startsWith('.openclaw/') ||const RULES_URL = 'https://raw.githubusercontent.com/AKforCodes/openclaw/main/scripts/jira-zero/bulk-rules.json'const html2pptx = require('C:/Users/AdamK/.openclaw/.claude/skills/pptx-skill/scripts/html2pptx.js');const html2pptx = require('C:/Users/AdamK/.openclaw/.claude/skills/pptx-skill/scripts/html2pptx.js');const html2pptxPath = 'C:/Users/AdamK/.openclaw/.claude/skills/pptx-skill/scripts/html2pptx.js';const html2pptx = require('C:/Users/AdamK/.openclaw/.claude/skills/pptx-skill/scripts/html2pptx.js');- **Subtree file counts — always include `worktrees/`.** When breaking down the total file count, sample: `forgeapps/node_modules`, `forgeapps/apps`, `forgeapps/.git`, `forgeapps/.claude`, `forgeapps/.openclaw`, **and `Documents/worktrees/`- **Legacy-dir-write drift.** A dir on disk whose name matches a `legacy dir` column in the grandfathered table (e.g. `openclaw-maintainer/`, `forgebooks-maintainer/`) and contains only artifact files (LOGS/REPORT/ERRORS/DASHBOARD/etc, no `- **Legacy-dir-write drift.** A dir on disk whose name matches a `legacy dir` column in the grandfathered table (e.g. `openclaw-maintainer/`, `forgebooks-maintainer/`) and contains only artifact files (LOGS/REPORT/ERRORS/DASHBOARD/etc, no `return process.env.BUSYLIGHT_HEALTH_DIR || path.join(homedir(), '.openclaw', 'busylight-health');return env.BUSYLIGHT_HEALTH_DIR || path.join(home, '.openclaw', 'busylight-health');The single health routine for the forgebot-mini Mac mini (macOS ARM64, hostname `forgebot-mini`). It is the core-health sibling of `adamobook-maintenance`, trimmed to what this machine actually has: the Claude desktop app and the Claude Cod- **Playwright only via `npx playwright` CLI** — never via Claude-in-Chrome MCP or OpenClaw browser; those aren't available in unattended runs.3. Columns it does not measure (`openclaw_status`, `adamobot_status`,* Columns this collector does NOT measure (openclaw_status, adamobot_status,**Dirty-working-tree case.** If `git pull --rebase` refuses because the working tree carries unstaged changes from a sibling routine (e.g. forgesales-maintenance staging GM project artifacts mid-session), do NOT commit those files on the si/^\.openclaw\/workspace\/work\/.*\/_old\/.*\.py$/.test(path),