agentleFS
rddmwmddrrddmwmddr/android-ad-cleaner/CLAUDE.md

android-ad-cleaner

CLAUDE.md7.1k starsChanged 19 days agoMITView on GitHub

本仓库的维护规范就是本文件:开工前读完,判断标准在 CODING_STANDARDS.md。AGENTS.md 不在这里——它是交付给用户侧执行 agent 的手机操作手册,不是维护规范(ADR-0028);但改引擎行为(挂包拒绝名单、极性词表、off() 的走向)时,§1 的 11 条产品契约就是这条改动的边界,先读一遍。 本文件只写会改变 agent 行为的指令。逐次变更记录见 CHANGELOG.md,用户看的更新说明与发版流程见 docs/agents/release.md,上报归类见 docs/09,不在这里复述。

Adopted by

Steady: 0 new projects took it in the last 4 weeks, none the 4 weeks before.thin data

Week of Sep 13: 0 new projectsWeek of Sep 20: 0 new projectsWeek of Sep 27: 0 new projectsWeek of Oct 4: 0 new projectsWeek of Oct 11: 0 new projectsWeek of Oct 18: 0 new projectsWeek of Oct 25: 0 new projectsWeek of Nov 1: 0 new projects
Sep 2026Oct 2026Nov 2026
New projects taking a version of this file each week, over the 8 weeks our latest run read: only 0 in all, so this is a hint, not a trend.
  • In this repositoryOne other file it gives its agents.

The file

Files
CLAUDE.md

CLAUDE.md

本仓库的维护规范就是本文件:开工前读完,判断标准在 CODING_STANDARDS.md。AGENTS.md 不在这里——它是交付给用户侧执行 agent 的手机操作手册,不是维护规范(ADR-0028);但改引擎行为(挂包拒绝名单、极性词表、off() 的走向)时,§1 的 11 条产品契约就是这条改动的边界,先读一遍。

本文件只写会改变 agent 行为的指令。逐次变更记录见 CHANGELOG.md,用户看的更新说明与发版流程见 docs/agents/release.md,上报归类见 docs/09,不在这里复述。

开发

  • 回归:python -m unittest discover -s tests;本机用仓库根的 .venv/bin/python(系统 python 缺 adbutils,会报一串 ModuleNotFoundError)。只装 requirements.txt 就够,不需要 pywebview / pillow。并行会话在各自的 worktree 里干活时,那个目录没有 .venv,用主副本 .venv/bin/python 的绝对路径;Read/Edit 也一律用该 worktree 的绝对路径。只跑一个文件时加 PYTHONPATH=tests:PYTHONPATH=tests python -m unittest tests.test_row(tests/ 里的用例按顶层模块 import fixtures)。
  • 本机 .venv 是 3.13(仓库根的 .python-version 钉着这一版),与 CI 的 Linux job 同一版,上面那条回归命令就是本机口径,不必再用别的解释器跑一遍;重建时照 .python-version 走,别升到更新的版本。3.12 只剩 Windows job 与发版打包在跑,而那两边会 skip 掉 POSIX-only 的一批用例(包括 CLI 逐字节对拍),macOS 打包不跑回归——解释器会改写部分输出(3.13 起编译器剥掉文档字符串的公共缩进,异常 repr、argparse 帮助同理),别假设两版逐字相同。
  • 数基线总数用干净副本:先 git rev-parse origin/main 记下 <sha>,再 git archive <sha> | tar -x -C /tmp/x,在 /tmp/x 里跑同一套。主副本里可能躺着别的会话没提交的用例。干净副本与新 worktree 都没有 node_modules,跑之前先 npm ci,否则前端用例那条会红在 Cannot find module 'jsdom'。
  • 改动面与审查对比用分支基点的固定 SHA(git merge-base HEAD origin/main 的结果,git diff <sha>),不用 origin/main 尖端——并行会话会推进它。
  • 主副本的当前分支随时被别的会话切走(main 只是其中一种状态),所以切分支、丢弃改动(git checkout --、restore、reset、stash)都在 git worktree add 出来的目录里做;主副本只做合并与只读操作。
  • 推送前再 git fetch origin main 并 rebase:并行会话会在开工到推送之间推进 main,基于旧 SHA 推送会让 PR 直接 CONFLICTING,CI 也不触发。
  • CI:.github/workflows/test.yml 在 PR 和 main 推送时自动跑同一套,Linux(unittest,3.13)与 Windows(unittest-windows,3.12)各一个 job,两版解释器各跑一次;两边 skip 的用例不一样(Windows 侧 skip 掉 POSIX-only 那批,含 CLI 逐字节对拍),判断覆盖时看 -v 输出里的 skipped 行,别假设两边跑的是同一批。build-windows.yml 只在 v* 标签或手动触发时打包,不守 PR。
  • 静态检查:uvx ruff@0.17.3 check --select F,E9 tool tests gui android/app/src/main/python,本地与 CI 同一个版本(CI 就钉 0.17.3,.venv 里没有 ruff)。不查 recipes/——机型脚本靠注入作用域执行,静态分析看到的全是未定义名;也不开格式与行长规则。
  • 找「前端行为测试」先看 tests/js/:用例用 node --test + jsdom 加载真实的 gui/web/index.html 与官网根目录的 index.html(下载页;手机版界面是 Compose,不在 jsdom 里测,判断在 aac_android/view.py,用 Python 测;ADR-0017)。由 tests/test_web_client.py 在 unittest 里代跑,回归仍是上面那一条命令;单跑先 npm ci,再 npm test(等价于 node --test --test-timeout=30000 --test-force-exit "tests/js/*.test.js";Node 22 不认目录参数,--test-force-exit 防漏写 window.close() 时挂住)。缺 node、用例数为 0 都判红,不跳过。jsdom 覆盖不到的真渲染 / 真定时器再退到真浏览器:python -m http.server 起静态服务,页面加载后桩 window.pywebview.api 并 dispatch pywebviewready,之后直接调 showRun() 这类顶层函数。
  • CHANGELOG 一条一行、≤ 80 字,落在 ## 未发布 的 ### 新增 / ### 修复 / ### 内部 之一,结尾挂一个编号(有 PR 挂 PR 号,只有 issue 的挂 issue 号;内部重构再加 ADR 号)。内部条目允许点一个符号名,但不展开机制;测试数、基线 SHA、对拍组数一律不写——那些在 PR 描述与 ADR 里。## 未发布 期间不写验证行,发版时才补。rebase 后先 git rebase --continue 把提交落完、再跑回归与对拍,并确认 ## 未发布 没有被已发版的小节吸收(main 刚发过版时要重新开出来)。
  • 审查标准:见 CODING_STANDARDS.md,只放判断项;机械规则交给 CI。
  • 社区问题的归类与真机缺口见 docs/09:那里只记 GitHub 上看不到的判据与缺口,逐条回复与 issue 编号留在 issue 里。
  • 找「命令怎么分派、退出码怎么定」先看 tool/run.py 的 dispatch() 与 COMMANDS:一条命令一个 cmd_*(serial, rest) -> int,sys.exit 只在 __main__ 一处;退出码语义见 ADR-0005。tool/adapt.py 的三条子命令同形状:取 run.fail() 与返回码(#708),改它们时别把 sys.exit 加回 helper。
  • 找「开关所属的行」先看 tool/row.py:line 结构定界、own 多开关容器收窄、title_of 平铺列表按竖直距离分带、title_hit 给出同一段标题文字的落点(off() 回退用)、dedupe 同一水平带(整行留最靠右、双列各成一行)、control 开关本体(卡片整体 checkable 时落点取内层 Switch);fast.py 的 switches() 消费 dedupe / control,chan_fast.py 共用 SAME_LINE 与 own,disabled_at 判开关是不是灰的(整卡或内层开关带 enabled="false"),off() 与 chan_fast 共用它,不要另写一份。设置入口(齿轮)的判据是 icon_hit,机型脚本从 fast 取这一份、不再各留副本。
  • 找「某个品牌某个分组的入口怎么进」先看 tool/entries.py:品牌家族 FAMILY 只在那里定义(run.py 的广告包、参考脚本与版本比较都从它取,别再建第二份),ENTRIES 是品牌 × 分组的三档入口,reach() 按直达 → 搜索回退、都不通返回 None,markdown() 生成 docs/清单/入口速查.md。条目必须有出处(机型脚本里用过,或某份品牌清单里写着),used_by() 从脚本现算「用过的机型」,speedups() 给入口速查表尾的「可提速提示」(同族有人用过、这台没用过的直达),tests/test_entries.py 守着这几条。
  • 找「这个开关该开还是该关」先看 tool/polarity.py:NEG_PREFIX / AD_WORDS / TRACK_WORDS 与 want_state() 只在那里定义,tool/fast.py 只是显式 re-export;加一个否定词会同时改变引擎与词库(ADR-0008 的增补段)。
  • 找「某个开关叫什么、哪一页要留着什么」先看 tool/vocab.py:从机型脚本现算每个 (家族, 分组) 的词条与同页保留项,生成 docs/清单/词库.md;只认 p.off() / close_named() 的字面量与模块级常量,一条词条都没读出来的脚本列在「读不到的脚本」。方向(要关 / 要开)取自 polarity.want_state(),不按调用名猜。同页保留项只在那一页成立,不产出跨页禁词表(ADR-0008)。写完脚本跑 python3 tool/vocab.py gaps <目录名> 查漏:同家族别的机型关过、这份没写的词条。
  • 找「按文字导航该用哪个方法」先看 docs/04-给新机型写脚本.md 的「该用哪个导航方法」:start / entry / enter / setting / go / tap / tab 失败时是 raise 还是返回 False,选错会点错地方;setting 失败只返回 False,这一段没兜底时必须 raise,否则本段空跑还按成功记(#776)。Phone.focus() 是当前前台窗口(多数是 包名/页面名,锁屏与通知栏抢焦点时是裸窗口名),不是焦点控件。
  • 找「适配新机型从哪一步开始」先看 tool/adapt.py:survey 只读试入口(只试 entries.ENTRIES 的直达、不走 Phone.start,落点用 entries.landed()),explore / gen / check 是后三段;-s 序列号 adapt <子命令> 的转发只认 ADAPT_SERIAL_SUBS(survey / explore / check);gen(不用带 -s)与未知子命令按这种形态调时,dispatch() 直接 fail(),不再静默打印帮助。
  • 改「各品牌在哪儿连点 7 下」先看 docs/手机版教程/brand-taps.json:这四行是单一来源,跑 python tool/gen_brand_taps.py 渲染进 android-tutorial.html、docs/手机版教程/README.md、docs/00-打开开发者模式.md 的 brand-taps 标记区,漏跑由 tests/test_doc_consistency.py 抓。标记区外的正文(如页面里「小米连点的是「OS 版本」」)仍是手写。
  • 改「官网两页的外观」先看仓库根的 site.css:调色板、深色档、顶栏与页脚只在那里,python tool/gen_site_css.py 把它渲染进 index.html 与 android-tutorial.html 的 site-css 标记区,页面不引外链(单文件副本取不到,ADR-0025)。两页在共享样式上的差异值只在 :root.reading 一条里(页面专属样式仍各自持有),漏跑由 tests/test_doc_consistency.py 的 SiteCssTests 抓。
  • 找「这一页该拨哪些开关」先看 tool/fast.py 的 plan_switches() 与 SwitchPlan:目标选择、屏带过滤、checked / kept / disabled 只在那里定义;灰态由调用方注入的 disabled= 谓词给出(off() 会复读一页确认),off() 只做点击 → 回读 → 重试 → 报告(连点前若屏上盖着确认框,先点掉再继续,判据是 _confirm_target;补点两轮仍不动时回退到点行标题,switch_rows() 的第四项与 pick_title_rows(),ADR-0024)。回读的结论由 readback() 给出(每条目标一个结局,词表见 CONTEXT.md 的「回读」),补点该点哪一行由 pick_retry_rows() 给出;两个函数都不读屏、不点击,page_same 与 disabled 由调用方注入。
  • 找「启动后算不算还在目标 App」先看 tool/fast.py 的 _launch() / check_foreground():unknown_focus() 判「读不出 ≠ 离开」,连续 FOREIGN_STREAK 帧外占才停段,启动等待按 LAUNCH_WAIT 计、顺延不超过 LAUNCH_HARD_STOP;只有确认落在目标 App 时才读页面文字、关弹窗(ADR-0022)。- 找「等页面认得出」先看 tool/wait.py:settle / setting / ChannelPage.refresh / off / confirm 都消费 until(),不要另写轮询循环;「等机主解锁」的文案、轮询间隔、站稳时间与默认预算只在同一文件的 wait_unlocked() 里,两处调用点(run.py 起脚本之前、Phone)只传锁屏判据与亮屏命令。
  • 找「怎么走到渠道页、认出哪一行的开关」先看 tool/chan_fast.py 的 ChannelPage.open():直达 / 转应用通知页 / 内联行 / 同名放弃四类只在那里定义(ADR-0007);channel_switch / inline_switch / wait_page / via_app_page 是一行前向壳,不要往里加逻辑。
  • 找「引擎报给客户端的状态」先看 tool/events.py:六个 kind 与事件行格式只在那里定义(ADR-0004),引擎侧 emit()、gui/app.py 的 _log() 都走它;failed_steps 是唯一带载荷的 kind,客户端用 parse_data() 取整份字典,其余仍用 parse() 取 kind。不要再按中文文案判断状态。
  • 找「这句话该说电脑还是说本 App」先看 tool/host.py:ON_PHONE / CLICKER / CLICK 只在那里定义(手机版由 aac_android/main.py 的 boot() 设 AAC_HOST=phone),tool/troubleshooting.py 是显式转发、tool/adb_link.py 直接取;客户端自己产出的诊断行同理,常量在 gui/app.py 的 TAP_REFUSED,由 boot() 覆盖,传给引擎的宿主标记只认 ENGINE_HOST、不继承用户 shell 的 AAC_HOST。分叉的只有措辞,唯一的控制流例外是手机版不写插电常亮(chan_fast.keep_awake()、run.py 的 recipe 与 finish),别让它变成按宿主分叉的判定(ADR-0019 的增补段)。读屏失败分两种结局,判据在 adb_link:LIB_GONE 认「命令服务断开」这一族(走 link_lost),read_failed() 认「读屏请求超时」(只报这一步没完成,后面的照常跑)。
  • 找「渠道怎么判营销 / 服务 / 受保护」先看 tool/channel_policy.py 的 classify():营销候选、扫描排除、默认不勾、受保护、厂商营销 ID、广告网络 ID、前台服务七组判定只在那里定义(ADR-0006);chan_fast 的扫描分支与 gui/app.py 的 chan_scan() 都消费它,不要另写词表。前台服务的证据来自渠道行的 mFgServiceShown(Android 14 起叫 mUserVisibleTaskShown,两个都认,见 FG_SERVICE_MARKS;parse() 用 foreground out 参数带回),不在通知记录段。
  • 找「怎么点 App 底部标签」先看 tool/fast.py 的 Phone.tab():底部带 top > 0.85H 与「精确 → 逗号末段等于 → 包含」三层匹配只在那里定义(ADR-0012);它不重试、不确认落点、找不到不回退,需要文字确认的普通导航仍用 Phone.go()。
  • 改「一行输出怎么进界面」先看两处:gui/app.py 的 _log() 决定它进 Job.lines 还是只当事件;gui/web/index.html 的 summarize() 在认不出模式时直接显示 results[].tail 末行——tail 是第二个落点,机器行不能进。手机版同样的判断在 android/app/src/main/python/aac_android/view.py,改口径时两边都要看。
  • 找「没勾的项为什么出现在结果里」先看 gui/app.py 的 plan_tasks():勾了的排 Task,没勾的排一条 skip_reason 非空的,由 not_run_result() 记成 rc=0 + skipped 的结果行(ADR-0023);原因分三档——没勾、这台机本来就没有或之前已做、通知没扫成,取自 Api._offered()(last_status + last_chans),不从 plan 的空字段反推。真因故障跳过的行仍是 rc≠0,别把它并进这一档。
  • 找「哪一步还能重试、重试重跑什么」先看 gui/app.py 的 retryable() / retry_plan():可重试 = rc≠0 且没 stopped(#577 的 rc=0 跳过与用户停止都不算),广告开关步只取结果行里的 failed_steps 段名,快照成功过就不重存(ADR-0026)。合并按 Task.kind 在 Job.add_result() 就地覆盖,两个宿主读同一个 poll() 的 retry 计数,别在前端或 view.py 再算一份;段名来自引擎的 failed_steps 事件(ADR-0004 增补段)。
  • 找「手机版界面」先看 android/app/src/main/java/com/ahuamiao/adcleaner/ui/AppModel.kt:页面流程只有 Screen 一个状态,每次切换都经过它的方法(ADR-0018);带判断的逻辑放 aac_android/view.py,别写进 Kotlin。手机版不再加载 gui/web/。
  • 找「手机版替换层」先看 android/app/src/main/python/aac_android/:adb.py 接管 subprocess 并按 adb 语义回答,bridge.py 是 shell 门面(Shizuku 或内置无线调试),inproc.py 在本进程线程里跑脚本(清 tool/ 模块、换环境变量、按线程分流输出、SystemExit 当退出码、看门狗只写 logcat),u2.py 顶掉 uiautomator2 / adbutils 并在本地匹配选择器(ADR-0019)。引擎、tool/、recipes/ 与桌面版同一份;新增读屏能力要先加进 u2.py 与 tool/reader.py 两边。
  • 造不连手机的 Phone 用 tests/fixtures.py 的 phone_stub()(fake_phone() 就是它加一条时间轴),装配只此一处。客户端用例要假 Runner(命令返回什么、spawn 交什么)同样用它:FakeRunner / FakeProc,Api(runner=…) 注入,不要 patch api._run 与 app.subprocess。纯重构要给对拍证据时,同一文件还有 all_pages() 取 tests/ 里的页面样本、Clock 假时钟、Timeline + Device 按时间轴换页。
  • 无设备用例不许真等:chan_fast 的 scan 分支会读型号,用例要 patch 掉 phone_model,否则对着不存在的序列号等 adb 超时;机型脚本一律用 fixtures.load_recipe() 装载(它把脚本的 time 三个读数一起换成假钟),自己 exec 一份脚本就会真 sleep。躲不开真实进程的环节(跨进程锁、真起播放器)用 Clock 注入或把等待压到毫秒级。tests/test_recipe_loader.py 守着装载这一条。
  • 改「认渠道页」这类读屏逻辑要做改前改后对拍时,驱动器是 tests/compare_chan_pages.py:认页 / 进页 / 编排三层 × 两种屏尺寸,同一份探针分别跑冻结基线与当前 tool/,守卫数字非零才算测到。
  • 找「读屏 adapter」先看 tool/reader.py:Phone.reader 是手机读屏库或假设备的统一接口,Phone.d 是它的历史别名(机型脚本与测试用),新增读屏能力先加进 Reader。
  • 手机上「有」的读屏异常名,电脑上未必有:aac_android/u2.py 的 install() 把模块里定义的类动态注册成 uiautomator2.exceptions,电脑上装的是真库 + adbutils。在 tool/、gui/ 里新增 u2.exceptions.X 或 adbutils.X 之前先确认桌面那份也有,tests/test_runtime_symbols.py 守着这一条。
  • adb 固定 platform-tools 37.0.1(gui/app.py 的 ADB_PINNED);升级时改那张表,校验值按 Google repository2-3.xml 的 SHA-1 核对。
  • 客户端数据路径看 gui/app.py 的 ClientData,备份目录看 tool/backups.py 的 Backups(root 由调用方给),工具模块用 _tool() 惰性取。
  • 找「Windows 启动失败是缺 WebView2、被 MOTW 拦还是托管的 dll 被判成远程来源」先看 gui/winpreflight.py:注册表三态、两个关键 dll 的 Zone.Identifier 判定与 load_rejected() 认的那两个原文子串只在那里定义(ADR-0003);gui/app.py 的 startup_advice() 只按结论选文案,顺序是缺运行时 → MOTW → 原文拒载 → 未确认 → 兜底(带 MOTW 的 dll 也报同一句 Failed to resolve,所以 MOTW 在前);startup_failed() 先经 win_clipboard() 把整段写进剪贴板再弹窗,写不进去才退回「按 Ctrl+C」(#811)。随包的 <exe>.config 由 gui/dotnet_config.py 写,windows.spec 收集完产物后调用。

错误日志上报

  • 用户说明见 docs/12。服务器、数据库、部署与运维信息只记在本机 CLAUDE.local.md 和 .private/,不进仓库。

发版

  • 完整流程与 Release 正文的写法见 docs/agents/release.md:正文是用户看的唯一权威,repo 里不留副本,README.md 的首段从它复制。
  • 新版本提示读官网的 android-ad-cleaner-latest.json,发版后要更新它(步骤记在本机 CLAUDE.local.md)。
  • 官网另有一份放在机主的服务器上,发版后同步,方法记在本机 CLAUDE.local.md。
  • 国内下载走 Gitee:python3 gui/upload_gitee.py <版本> 从公开的 GitHub Release 下载安装包并核对 SHA256,推代码和标签,建发行版传附件,再匿名下载回来核对。令牌在本机 ~/.config/gitee/token,不进仓库和对话。百度网盘暂停使用;Gitee 不可用时把 index.html 的 REL.gitee 留空,改跑 gui/upload_baidu.sh [版本],它回写网盘链接、按钮随之恢复,#dl-lead 那句文案要手动改回「国内下载走百度网盘,链接里带提取码」,后半句「安装版会原地替换旧版,原来的备份保留;免安装版不会」原样留着。
  • 发完版按 docs/agents/release-followup.md 把 waiting-for-verify 的 issue 逐条发给报告者复测。新版不送到报告者手上,这些 issue 永远关不掉。

Agent skills

Issue tracker

GitHub Issues(gh CLI)。开工前先有票:任何实现 / 重构 / 文档改造先开 issue,分支名带 issue 号。见 docs/agents/issue-tracker.md。

Issue claiming

一张票在动之前先打 in-progress(gh issue edit <N> --add-label in-progress),同时摘掉 ready-for-agent / ready-for-human / needs-triage。动手前先 gh issue list --label in-progress 查重:命中一张不是本会话认领的票,先看它有没有开着的 PR 或在改的分支,别开第二份实现。合入 main 之前不摘:PR 开着没合并,别人仍可能拿同一张票再做一遍。摘只有两个时机——合入 main 且不需要真机复测就直接摘,合入 main 但等真机复测就摘 in-progress、加 waiting-for-verify(两者不并存);放弃或改派则摘掉并把原来的 ready-* 或 needs-triage 加回,票面写一句为什么停。细节见 docs/agents/issue-tracker.md 的「票的生命周期」。

Triage labels

默认五个角色标签,标签名即角色名;另加本仓库自有的两个状态标签:waiting-for-verify(已修、等真机复测)与 in-progress(已认领、正在改)。见 docs/agents/triage-labels.md。

Release followup

发版后要催哪些复测、报告者确认前不关闭哪些 issue,见 docs/agents/release-followup.md。每次发版都要过一遍这张清单。

Code review

派审查的方法与规则见 docs/agents/code-review.md:基线钉 SHA、评审期间不改工作区、默认三轴。

Domain docs

single-context:根目录 CONTEXT.md + docs/adr/。见 docs/agents/domain.md。CONTEXT.md 只放术语表(命令 / 脚本 / 清单与词库 / 执行 / 连接 / 事件 / 等待 / 通知 / Issue 状态 / 规则 / 文档十一组定义);模块边界的决定写进 docs/adr/(现有 0001 手机连接、0002 Phone 状态、0003 客户端 import 与依赖、0004 引擎状态事件、0005 命令与退出码、0006 渠道判定、0007 渠道到达、0008 拨动计划、0009 引擎载荷通道、0010 执行状态、0011 Api 拆分、0012 底部标签、0013 设置入口、0014 手机 shell 通道、0015 配对码识别、0016 设置搜索直达、0017 前端测试基座、0018 手机版界面、0019 手机版执行宿主、0020 不做读写拆分、0021 回读结局、0022 启动前台归属、0023 没执行的项进结果、0024 落点回退、0025 官网共享样式、0026 结果页重试、0027 守护模式、0028 两个 agent 受众)。整体形状看 docs/ARCHITECTURE.md:三个宿主、四条跨边界契约、模块清单;机制与取舍仍在 ADR 里,总览不复述。

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.