Forgeapps Engineering Audit · July 5, 2026

The Lean, Vanilla Monorepo

Full findings behind the Top-10 playbook deck: four parallel audit agents measured how lean, standard, and cross-agent-legible forgeapps is for Codex, Claude, and Gemini CLI agents — every number below was measured in this repo this week.

Adam: Do These · In This Order · Updated July 5, 2026

Exactly What I Need From You

The universal shortcut: for every item below, you only have to do the clicks behind your login and copy the new value — then paste it to me in chat. I place it in Doppler and the runtime file, restart what needs restarting, and verify the old credential is dead. You never have to touch Doppler or an env file yourself. (The full commands are listed anyway in case you prefer.)

1 · Regenerate your GitHub tokenLEAKED & LIVE

Verified minutes ago: it authenticates as adamkane (your main account) with near-total admin scopes — org admin, delete-repo, enterprise. This is now the most dangerous exposed credential.

  1. Be logged into GitHub as adamkane, open github.com/settings/tokens (Personal access tokens → Tokens (classic)).
  2. Find the classic token with the huge scope list (Last used: today) → click its name → Regenerate token → enter your password when asked → copy the new ghp_… value.
  3. Paste the new value to me in chat — or run doppler secrets set GITHUB_TOKEN --project forgeapps --config prd (it prompts; paste, Enter) and replace the GITHUB_TOKEN= line in C:\Users\AdamK\Documents\forgeapps\.hermes\.env.
  4. Tell me "github done" — I re-test the old token and confirm it's dead. Recommended while you're there: this token's scopes are far broader than the bots need — consider minting a lesser-scoped replacement instead of a like-for-like regenerate.

2 · Rotate ForgeBot's two Slack tokensLEAKED & LIVE

Verified minutes ago: the leaked bot token still authenticates as forgebot on team forgefx. Or skip all of this — say "go slack" and I drive it through your browser.

  1. Open api.slack.com/apps → click ForgeBot.
  2. Left menu: OAuth & PermissionsReinstall to Workspace → Allow. Copy the new Bot User OAuth Token (xoxb-…).
  3. Left menu: Basic InformationApp-Level Tokens → click the token → Regenerate. Copy it (xapp-…).
  4. Paste both to me — or set Doppler SLACK_FORGEBOT_BOT_USER_OAUTH_TOKEN, SLACK_BOT_TOKEN (the xoxb) and SLACK_FORGEBOT_APP_LEVEL_TOKEN (the xapp), plus the SLACK_BOT_TOKEN= / SLACK_APP_TOKEN= lines in .hermes/.env, then restart Hermes.
  5. Heads-up: ForgeBot is quiet in Slack from the reinstall until the new values land and Hermes restarts (minutes, if you paste them to me).

3 · Replace the Anthropic API key

Create the new key before disabling the old one and there's zero downtime. Your Claude Code / Cowork sessions are unaffected either way (different auth).

  1. Open console.anthropic.com/settings/keysCreate Key → copy it (sk-ant-…).
  2. Paste it to me — or replace the ANTHROPIC_API_KEY= and ANTHROPIC_TOKEN= lines in .hermes/.env (no Doppler home today; I'll add one when I place it).
  3. Back in the console: Disable the old key. Tell me "anthropic done".

4 · Regenerate four search/scrape keys

Or say "go keys" and I drive all four dashboards through your browser.

  1. openrouter.ai/settings/keys — delete + recreate the key → paste to me (Doppler OPENROUTER_API_KEY + env file).
  2. dashboard.exa.ai → API Keys — same (EXA_API_KEY).
  3. firecrawl.dev/app → API Keys — same (FIRECRAWL_API_KEY).
  4. app.tavily.com → API Keys — same (TAVILY_API_KEY).

5 · Regenerate the Browserbase key

  1. browserbase.com → Settings → API Keys → regenerate → paste to me (env file only; no Doppler home).

6 · Green-light the git history rewrite

  1. After items 1–5 are done, reply: "go rewrite tonight" (or name a window). I run the rewrite, force-push, and resync every machine — you do nothing else.
  2. Until then the old values remain readable in the repo's history: already dead for Google, live for items 1–5 until you rotate them.

7 · Optional, one click, in a few days

  1. Open the adamkane-workspace-mcp client → delete the disabled old secret (ends AMmm). It's already verified dead, so no rush and no risk.
~9ktokens auto-loaded before any work
1,810CLAUDE.md files tracked in git
1.88 GBpaid by every clone
63apps in the workspace glob

Act-today security finding — ADDRESSED July 5, 2026. Original finding: a tracked Codex config carried a live Google OAuth client secret, and .hermes/.env (holding ~10 other live keys) was tracked via deliberate ignore-rule exceptions. Sweep also found the YouTube client's secret and refresh token committed. Done: workspace client secret rotated (old one disabled, verified dead); leaked YouTube client deleted outright and recreated fresh with new consent; all secret-bearing files untracked, docs redacted, ignore rules fixed, configs now pull from Doppler. Still open: the values live on in git history until the one-time rewrite (move #5), and the ~10 non-Google keys from the old tracked .env (Slack, GitHub, Anthropic, OpenRouter, Exa, Firecrawl, Tavily, Browserbase) should be rotated.

The Playbook

Top 10 Moves on One Page

Click any row (or focus it and press Enter) to expand the full detail — why it matters, what the audit measured, and the first move.

#MoveFirst actionEffortImpact

Audit Track 1 of 4

How Vanilla Is It? — Orientation Cost for a Fresh Agent

Instruction-file sprawl: 1,808 CLAUDE.md files and a 14-file auto-import chainHigh

Evidence1,808 CLAUDE.md files (13,467 total lines) outside node_modules — 1,391 under apps/ alone (forgebooks has 128, jd 89, forgesales 64). Most are 3-5 line boilerplate stamps. The root chain auto-loads 14 files (~33 KB ≈ 8-9k tokens) before any work. Root also holds 12 more CLAUDE_*.md files including CLAUDE_SCHEDULED_TASKS_RULES.md at 1,083 lines / 122 KB.

FixCollapse the auto-import chain into one root CLAUDE.md under ~150 lines with on-demand pointers into docs/. Stop stamping per-directory stubs; keep CLAUDE.md only at root and per-app root.

Core behavioral instructions live in .openclaw/workspace/, invisible to non-Claude agentsHigh

EvidenceIDENTITY.md, SOUL.md, USER.md, AGENTS.md, HEARTBEAT.md, TOOLS.md sit in .openclaw/workspace/ — reachable only via Claude-specific @-import syntax. Codex reads AGENTS.md, Gemini reads GEMINI.md; neither follows @-imports. GEMINI.md count in the repo: 0. The same dir mixes in unrelated content (DREAMS.md 954 lines, BAE-MEMORIES.md 416 lines, reports).

FixPromote the operative rules into root AGENTS.md (the cross-CLI standard); make CLAUDE.md a thin pointer. Move persona/memory/report files out of the instruction directory.

Root has ~73 entries; heavy custom surface, no README, no root tsconfigHigh

Evidence49 visible + 24 dot-entries at root. Nonstandard: .forgebot/ (276 MB), .openclaw/, .hermes/, .codex/, .qmd/, .remember/, crons/, channels/, swat/, lost_n_found/, both output/ AND outputs/, FIX-FORGEMEDIA.bat. No README.md, no root tsconfig/turbo/nx. The repo ships a .rootallowed file to police its own root drift.

FixPromote CONTEXT.md (good 52-line orientation doc) to README.md. Merge output/ into outputs/, remove root clutter, fold agent-runtime dot-dirs into one location.

Skill system is a custom multi-runtime symlink web with a nonstandard SUBSKILL.md conventionMedium

Evidence.forgebot/skills is the physical home (223 SKILL.md, 368 SUBSKILL.md, 276 MB). Four symlinks point at it. SUBSKILL.md is a house-only convention no harness auto-discovers. pnpm-workspace.yaml registers 8 skill script dirs as workspace packages, so package tooling depends on symlink resolution on Windows.

FixDrop skills-as-workspace-packages from pnpm-workspace.yaml; document the symlink layout in one place; collapse SUBSKILL.md indirection where a subskill could be a plain skill.

Workspace config duplicated and divergent between pnpm-workspace.yaml and package.jsonMedium

Evidencepnpm-workspace.yaml lists packages/*, apps/*, crons, scripts, plus 8 .claude/skills paths. Root package.json ALSO has a npm-style "workspaces" field (ignored by pnpm) listing a different subset. An agent reading package.json first gets the wrong picture.

FixDelete the "workspaces" field from root package.json; keep pnpm-workspace.yaml as the single source, trimmed toward apps/* and packages/*.

Root package.json has no standard entry-point scriptsMedium

EvidenceNo dev, build, test, lint, or typecheck at root. Instead: sentry, image-gen, openrouter, share-preview, vercel:queue-slo — all skill utilities, several requiring Doppler. Per-app package.json is fine (forgesales has dev/build/preview/typecheck/lint/test — vanilla Vite).

FixAdd conventional root scripts that fan out (pnpm -r build etc.); move skill utilities into the skills' own package.json files.

64 app dirs with dead weight and typo-duplicatesMedium

Evidenceapps/justbcappy and apps/justbecapy both exist — a typo'd near-duplicate pair. Stray untracked build artifact at session start: apps/forgemail/vite.config.ts.timestamp-*.mjs.

FixArchive or delete dead/duplicate apps; move retired apps out of the workspace glob; gitignore vite timestamp files.

Committed automation exhaust: crons/ routine artifacts live in gitMedium

Evidence36 routine dirs each accumulate per-run artifacts (LOGS.md, REPORT.md, DASHBOARD.html). Recent commit history is dominated by "refresh artifacts" churn; the Multi-Agent Safety rules exist largely to manage it.

FixKeep ROUTINE.md specs in git; move run outputs to a gitignored dir or external store so history reflects code, not cron heartbeats.

House rules that invert agent defaults are scattered and repeatedMedium

EvidenceDeploy-only-via-git-push, Doppler-only secrets, trunk-only, never-stash, no-Python, CalVer — spread across CLAUDE_MISC.md, CLAUDE_PRINCIPLES.md, TOOLS.md, AGENTS.md, and re-stamped as banners in app files. The deploy rule appears in at least 4 auto-loaded files.

FixOne short "House rules (differ from defaults)" block — 8-10 bullets — near the top of the root instruction file; delete every duplicate.

No CI-discoverable build orchestration; ports live in a custom launch registryLow

EvidenceNo turbo.json/nx.json, no root .github/workflows. App ports live in .claude/launch.json and per-app dev scripts. A fresh agent cannot run "the whole repo" or find a canonical repo-wide check.

FixAdopt a minimal repo-wide pipeline (build, typecheck, test) or document that the unit of work is one app; mirror the port table into the README.

Audit Track 2 of 4

Bloat — What Every Clone, Search, and Status Check Pays

~1 GB of images and media committed as plain git blobs at HEADHigh

Evidence24,284 tracked files / 1,309 MB at HEAD. By extension: .png 1,516 files / 774.5 MB, .jpg 402 / 144.5 MB, .ttf 429 / 60.9 MB, .glb 59 / 48.1 MB, .pdf 73 / 21.7 MB. LFS covers only 128 files and the budget is exhausted. Directly contradicts the repo's own "large assets go to ForgeMedia, not Git" rule.

FixRelocate non-deploy-critical media to the ForgeMedia CDN; add a pre-commit size gate (block new blobs >500 KB outside an allowlist).

Git history carries ~4.7 GB of dead blob content; every clone pays 1.88 GBHigh

EvidencePack size 1.88 GiB, 188k objects; .git is 2.1 GB on disk. 82,278 blobs total 6.02 GB uncompressed across history vs 1.31 GB at HEAD — roughly 4.7 GB is deleted content still in the pack.

FixOne-time history rewrite (git filter-repo / BFG) stripping historical media, then the documented resync procedure. Until then: clone with --filter=blob:none --depth=1.

1,810 tracked CLAUDE.md files — instruction sprawl agents auto-ingestHigh

Evidence1,810 tracked CLAUDE.md (plus 53 AGENTS.md). Depth histogram: 620 at depth 3, 623 at depth 4, 369 at depth 5 — despite the policy cap of "delete depth 4+". Claude loads every CLAUDE.md on the path to any file it touches.

FixEnforce the existing depth cap mechanically; delete stubs that restate the directory name; target under ~100 total, with a CI check.

10,266 tracked markdown files — 42% of the repo by file countMedium

Evidence.md is the largest tracked type by count (87.8 MB): 4,530 under apps/, 3,121 under .forgebot/, 815 under crons/. 10k+ tracked files live in hidden dot-dirs that default ripgrep skips — git tracks 24,284 files but rg --files sees only 14,120, so agents miss 40% of the repo or pay extra to search hidden trees.

FixTreat machine-generated markdown as data: datastore or untracked dir. Prune retired skills — a leaner .forgebot/skills is the single biggest markdown win.

Routine cron artifacts churned into git: 35.5 MB of logs, one file rewritten 605 timesMedium

Evidencecrons/ holds 1,182 tracked files (50.9 MB); 551 are LOGS/IMPROVEMENTS/history files totaling 35.5 MB. crons/routines/docs-maintenance/LOGS.md is a single 2.45 MB markdown file with 605 commits touching it. 37 HTML dashboards tracked.

FixCap LOGS.md with rotation to an off-git archive; stop committing "pre-prune" snapshot copies — git history already is the snapshot.

159 MB of byte-identical files tracked at multiple paths; brand fonts committed 8-11 timesMedium

Evidence1,321 duplicate-blob groups waste 159.2 MB in the checkout. Identical 3-5 MB deck PNGs exist three times across -v2/-v3 dirs; 429 tracked .ttf but only 127 unique basenames — JetBrainsMono-Regular.ttf appears 11 times, Oswald/OpenSans weights 8-9 times each.

FixOne canonical font/asset location; apps copy at build time or reference by URL. Delete versioned deck directories; dedupe skill example media.

63 workspace apps, many one-off or dead, including the typo-twin pairMedium

EvidenceAll 63 glob into the pnpm workspace (68 node_modules dirs materialize). Lifetime commit counts expose one-offs: justbcappy 5, forgesweep 10, public 12. The justbcappy/justbecapy twins jointly carry 44 tracked files / 32 MB, mostly duplicated map-art PNGs.

FixMerge the twins; adopt an archive policy — apps with no intentional commits in 90 days move out of the workspace.

Root-level instruction clutter: 27 files at root, 16 of them agent-instruction markdownMedium

EvidenceAGENTS.md, CLAUDE.md plus 13 CLAUDE_*.md siblings, CONTEXT.md, CONTEXT-MAP.md, GIT-CHECK.md, VISION.md, MINI_DESIGN_SYSTEM.md, FIX-FORGEMEDIA.bat. The @-import chain pulls a large fixed context block into every session.

FixFold the CLAUDE_*.md satellites into docs/ keeping only CLAUDE.md, AGENTS.md, README-grade files, and workspace configs at root.

.gitignore drift: duplicate rules, tracked-but-ignored files, no vite timestamp patternLow

Evidence405-line .gitignore with duplicated entries (.vercel three times). 76 files (11.1 MB, including 74 fonts) remain tracked under .claude/scratchpad/ though the directory is ignored. No pattern for Vite crash-leftover timestamp files.

FixDedupe the file, de-index the scratchpad, add vite.config.*.timestamp-* per Vite's documented recommendation.

node_modules layout is healthy; on-disk size claims in docs are staleLow

Evidencepnpm hoisting works: one 1.7 GB store, per-package symlink farms total only 367 MB. No node_modules/dist tracked in git. But the working-memory doc says "12 GB, 85k+ files" while measured reality is 6.8 GB — overstating by ~2x miscalibrates agents' traversal caution.

FixNo layout change. Update the size claim to the measured figure or defer to a live command per the docs-rot rule about counts in prose.

Audit Track 3 of 4

Cross-Agent Compatibility — What Breaks Codex and Gemini

Gemini CLI gets zero project instructions: no GEMINI.md and no .gemini/ anywhereHigh

EvidenceRoot has CLAUDE.md and AGENTS.md, but zero GEMINI.md and no .gemini/ dir. Out of the box Gemini reads only GEMINI.md context files — so it starts with none of the repo's rules: not Doppler-only secrets, not deploy-by-git-push, not the multi-agent git safety rules.

FixDon't write a third fork. Add .gemini/settings.json with "context": {"fileName": ["AGENTS.md"]} so Gemini consumes the same canonical file Codex does.

Binding rules live behind Claude-only @-import syntax; other agents get pointers, not contentHigh

EvidenceBoth root CLAUDE.md and AGENTS.md rely on @-imports that only Claude Code auto-injects. The Doppler rule, deploy rule, No-Fakes principle, and git safety rules exist ONLY in imported files — AGENTS.md's own body never states them. Whether Codex/Gemini chase those references is model-effort-dependent, not guaranteed.

FixInline the 5-6 load-bearing rules directly into the AGENTS.md body in ~20 lines; keep @-imports as a Claude optimization, not the delivery mechanism.

Repo violates its own Doppler-only secrets rule in the non-Claude agent configsHigh

EvidenceTracked .codex/config.toml contains a literal Google OAuth client secret plus client ID and email. Tracked .hermes/.env (24 KB) is force-included by !.env gitignore exceptions, despite the "never use .env files" rule. Any agent that reads the rules then reads the tree finds direct counterexamples — and learns the rules are optional.

FixMove the OAuth secret to env-var indirection sourced from Doppler; untrack .env and .env.bak.*; remove the gitignore exceptions; rotate the exposed secret.

Codex hook config points at a nonexistent path; machine-specific absolute paths committedMedium

Evidence.codex/hooks.json invokes scripts under C:\Users\AdamK\forgeapps\ — a path that does not exist (repo lives under Documents\forgeapps), so both hooks silently no-op. .agents/README.md hardcodes a Mac path as "this checkout".

FixDelete or repair the hook config with repo-relative paths; scrub committed machine-specific absolute paths per the machine-agnostic-docs rule.

Root AGENTS.md instructs Codex to load a slash command that does not existLow

EvidenceAGENTS.md line 39 points at .claude/commands/open.md; the commands directory is empty. The slash-command surface referenced by the instruction chain was emptied without updating pointers.

FixRemove the bridge section or restore the file; add a docs-maintenance check that instruction-file references resolve.

No root README and no canonical build/test/run document any agent finds immediatelyHigh

Evidence20 root .md files but no README.md. CONTEXT.md is good orientation but has zero build/test/run commands; the actual commands are scattered across CLAUDE_MISC.md, package.json scripts, and per-app configs.

FixShort root README: what the repo is, prerequisites, install/dev/build/test, and one line — "Agent rules: AGENTS.md." Repoint root scripts to physical paths so they survive a broken symlink.

Symlink skill-sharing is healthy but fragile on fresh Windows clones; many skills assume Claude-only toolsMedium

EvidenceAll five runtime links verified as real symlinks with correct targets. But a fresh Windows clone without Developer Mode checks them out as plain text files, silently breaking skill discovery. 128 matches for Claude-only tool patterns across sampled skills — Codex/Gemini invoking them would call tools that don't exist in their harness.

FixPost-clone doctor script (verify links, recreate as junctions); compatibility notes in SKILL.md frontmatter so non-Claude agents degrade gracefully.

Audit Track 4 of 4

Industry Best Practices (2025-2026) — What Good Looks Like

Adopt a root AGENTS.md — the cross-tool open standard

Stewarded by the Agentic AI Foundation under the Linux Foundation; created jointly by OpenAI Codex, Amp, Google Jules, Cursor, and Factory. Read natively by Codex, Cursor, Copilot, Windsurf, Amp, Devin, Aider, Zed, Jules, JetBrains Junie; Claude reads it too; Gemini can be pointed at it via settings. Adopted by 40,000+ open-source projects. Nested AGENTS.md is supported — OpenAI's own monorepo uses 88 of them.

Keep the root instruction file under ~100-150 lines

Practitioner consensus: 80-120 lines is the practical ceiling; models reliably follow ~150-200 distinct instructions per context and the harness system prompt already consumes ~50 slots. An ETH Zurich study found LLM-generated context files reduced task success ~3% on average and raised inference cost >20% — bloat is actively negative. Named anti-pattern: @-importing documentation into the root file.

Progressive disclosure: layered docs pulled on demand

Root file = always-true rules; nested per-directory files = local context loaded only in that subtree; referenced docs = read only when relevant. Skills follow the same principle — names/descriptions at startup, bodies on invocation. Test for every startup-loaded line: "does this apply to the majority of sessions?"

Uniform one-command verification entry points

The Commands section is the single most impactful AGENTS.md content because wrong-command guessing is where agents waste the most turns. Identical script names in every package, root fan-out, and the same four commands as the CI gate verbatim.

Fast, cached, affected-only feedback loops

"Agents work faster, produce better results, and operate more autonomously when they get immediate feedback on every change." Task caching means most tasks on a change hit cache; affected-project detection runs only impacted packages. Target: full loop under ~60s, per-app under ~10s.

Vanilla npm scripts beat bespoke wrappers and DSLs

Agents are trained on millions of repos using standard package.json scripts; custom task runners are exactly where they make the most mistakes. The industry direction (Turborepo positioning included) is accelerating standard scripts, not inventing new verbs. If a command needs a paragraph of explanation, rename or simplify the command.

Lean git: no binaries in history, no committed artifacts, aggressive .gitignore

Repeated binary commits can turn a 500 MB repo into 10 GB and degrade every operation. For agents this compounds: bloated trees slow the constant ripgrep/glob searches, and committed generated artifacts create noisy git status agents must reason around. Audit periodically with git-sizer.

Determinism: lockfile, pinned package manager, frozen installs, formatter

Committed pnpm-lock.yaml + --frozen-lockfile in CI are table stakes; the packageManager field makes the pnpm version machine-readable so agents don't guess npm and corrupt the lockfile. Prettier + .editorconfig keep AI diffs readable.

Navigation aids: identical per-app layout, apps/ vs packages/ split, README per app

The layout agents have seen most in training data. Consistency is the real aid: same src/, same script names, same config locations — an agent that has learned one app has learned all of them. Keep naming boring: folder name = package name = deploy target.

Sequencing

Start Here

TODAY
Rotate the exposed OAuth secret and untrack the .env files (#10).
THIS WEEK
Root build / test / typecheck / lint scripts (#4) · AGENTS.md pointer chain for all three agents (#1) · gitignore cron exhaust (#6).
THIS MONTH
Session-start context diet (#2) · CLAUDE.md stub sweep (#3) · root README and dead-app prune (#7).
THIS QUARTER
Media exodus to ForgeMedia plus the one-time history rewrite (#5) · canonical app skeleton (#8) · fast cached verification (#9).

Every convention you delete is context you get back.