编辑
2026-04-05
记录知识
0
请注意,本文编写于 35 天前,最后修改于 34 天前,其中某些信息可能已经过时。

目录

介绍
演示
总结
参考

看代码一直是一个枯燥的事情,那关于熟悉代码,是不是有一个不错的skill呢,实际上是有的,今天要介绍的一个skill:understand anything,它能够让我们轻松的理解一个代码仓库

介绍

Understand Anything 通过多智能体(multi-agent)架构分析你的项目,构建包含文件、函数、类以及依赖关系的知识图谱,并提供一个可视化交互界面,帮助你理解整个系统。不再“盲读代码”,而是从全局视角理解系统结构。

他比较适合如下几类人群

  • 程序员: 不再枯燥的看代码了,而是通过结构化引导逐步理解系统架构
  • 产品经理: 无需阅读代码,也能理解系统逻辑。直接开问即可
  • 代码维护者: 更新代码前使用/understand-diff,深入模块编写时使用/understand-explain,架构分析问题时使用 /understand-chat

简单来说,就是这个skill直接替代了人阅读代码的过程,让ai准确无误的分析代码后,告诉你代码的具体实现和原理细节。 适合所有与代码有相关工作的角色

image.png

演示

下面以linux开源的shadow程序为例,解析其中login命令的实现细节。

首先安装

/plugin marketplace add Lum1104/Understand-Anything /plugin install understand-anything /reload-plugins

到这里我们就可以开始调用skill来理解仓库了

 /understand src/

先启动了一个agent来代码扫描

● Now dispatching Phase 1 — project-scanner subagent scoped to src/. understand-anything:project-scanner(Scan src/ directory) ⎿  Read(.understand-anything/intermediate/scan-result.json) Update(.understand-anything/tmp/ua-project-scan.js) Update(.understand-anything/tmp/ua-project-scan.js) +2 more tool uses (ctrl+o to expand) (ctrl+b to run in background)

现在开始第二阶段,文件分析 agent

● Phase 1 complete. 45 files in src/. Now reading the scan result to batch files for Phase 2. Read 1 file (ctrl+o to expand) ● 45 files, all C code and Makefiles with empty import maps. Let me batch them and dispatch Phase 2 — file-analyzer subagents (2 batches of ~22-23 files, 5 concurrent).

第三阶段,开启评估器agent

● Merge complete (85 nodes, 64 edges). Now proceeding to Phase 3 - Assemble Review.

第四阶段,架构分析agent

● Phase 3 review passed with no issues. Now proceeding to Phase 4 - Architecture analysis.

第五阶段,检查输出

● Architecture complete (8 layers identified). Now Phase 5 - Tour.

终于完成了,花费了30分钟

● --- Analysis Complete Project: shadow (shadow-utils) Description: Shadow password suite — a C project providing user account management utilities (useradd, usermod, userdel, groupadd, etc.) built with GNU Autotools. Files Analyzed: 48 ┌──────────┬──────────────────────────────────────────────┐ │ Category │ Count │ ├──────────┼──────────────────────────────────────────────┤ │ code │ 46 (.c source files + Makefiles) │ ├──────────┼──────────────────────────────────────────────┤ │ config │ 2 (.indent.pro, .claude/settings.local.json) │ └──────────┴──────────────────────────────────────────────┘ Graph Stats ┌───────┬─────────────────────────────────────┐ │ │ Count │ ├───────┼─────────────────────────────────────┤ │ Nodes │ 85 (46 file, 38 function, 1 config) │ ├───────┼─────────────────────────────────────┤ │ Edges │ 64 (38 contains, 26 exports) │ └───────┴─────────────────────────────────────┘ Layers Identified: 8 ┌───────────────────────────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ Layer │ Files │ ├───────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ User Management │ 10 files (useradd, usermod, userdel, id, groups, chage, chfn, chsh, newusers, newgrp) │ ├───────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ Group Management │ 9 files (groupadd, groupdel, groupmod, groupmems, grpck, grpconv, grpunconv, gpasswd, chgpasswd) │ ├───────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ Password Management │ 5 files (passwd, pwck, pwconv, pwunconv, chpasswd) │ ├───────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ Login and Authentication │ 7 files (login, su, suauth, sulogin, logoutd, nologin, login_nopam) │ ├───────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ Security and Audit │ 2 files (faillog, lastlog) │ ├───────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ Subordinate ID Management │ 7 files (newuidmap, newgidmap, new_subid_range, free_subid_range, getsubids, get_subid_owners, check_subid_range) │ ├───────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ Utilities │ 3 files (cppw, expiry, vipw) │ ├───────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ Configuration │ 4 files (Makefile.am, Makefile.in, .indent.pro, Claude settings) │ └───────────────────────────┴───────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ Tour Steps: 12 Warnings - 19 orphan nodes (files with no edges — expected for a flat CLI utility project with no internal imports between files) Output: .understand-anything/knowledge-graph.json ✻ Cooked for 24m 17s

注意,这次生成之后,保存了本地,后续我们直接使用就行了。不是一次性的。下面演示解析login.c的功能

❯ login.c的具体实现细节是什么 ● Skill(understand-anything:understand-explain) ⎿  Successfully loaded skill

可以看到,加载了understand-explain为我输出

● login.c 实现详解 login.c 是 shadow 项目中用户登录认证程序,负责终端设置、PAM 认证和 utmp/utmpx 会话跟踪,复杂度为 complex(1368 行)。 --- 1. 架构角色 位于 Login and Authentication 层(登录和认证层),是系统身份验证的第一道入口。它与其他同层程序的关系: ┌───────────────────────┬──────────────────────────────────┐ │ 组件 │ 作用 │ ├───────────────────────┼──────────────────────────────────┤ │ login.c │ 本地终端登录认证(本文分析对象) │ ├───────────────────────┼──────────────────────────────────┤ │ su.c │ 权限提升(substitute user) │ ├───────────────────────┼──────────────────────────────────┤ │ sulogin.c │ 单用户模式恢复 │ ├───────────────────────┼──────────────────────────────────┤ │ suauth.c │ su 的 PAM 框架支持 │ ├───────────────────────┼──────────────────────────────────┤ │ logoutd.c / nologin.c │ 会话访问控制 │ └───────────────────────┴──────────────────────────────────┘ --- 2. 核心数据结构(全局变量) const char *Prog; // 程序名 ("login") static const char *hostname; // 远程主机名 static char *username; // 用户名 static int reason; // 登录原因 (PW_LOGIN / PW_TELNET / PW_RLOGIN) static bool fflg; // -f: 预认证跳过 static bool hflg; // -h: 远程主机登录 static bool rflg; // -r: rlogin 协议 static bool pflg; // -p: 保留环境变量 static bool amroot; // 是否以 root 运行 static struct faillog faillog; // 失败登录记录 --- 3. main() 函数流程 程序有两条执行路径:USE_PAM 和 非 PAM(传统方式)。 阶段一:初始化与标志处理 int main(int argc, char **argv) { sanitize_env(); // 清理危险环境变量 setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); amroot = (getuid() == 0); // 检查是否 root process_flags(argc, argv); // 解析 -f, -h, -r, -p 选项 // 必须运行在终端上 if ((isatty(0) == 0) || (isatty(1) == 0) || (isatty(2) == 0)) exit(1); 命令行标志: - -f name — 预认证登录(跳过密码验证,仅限 root) - -h hostname — 远程主机登录(telnetd 等) - -r hostname — rlogin 协议自动登录 - -p — 保留继承的环境变量 阶段二:终端设置 setup_tty(); // 配置终端:ICANON/ECHO/ISIG,读取 login.defs 中的 ERASECHAR/KILLCHAR umask(getdef_num("UMASK", GETDEF_DEFAULT_UMASK)); // 设置文件创建掩码 setup_tty() 的关键操作: termio.c_lflag |= ISIG | ICANON | ECHO | ECHO | ECHOE; termio.c_iflag |= ICRNL; // 回车换行转换 STTY(0, &termio); // 应用终端设置 阶段三:认证(PAM 路径 vs 传统路径) PAM 路径 (USE_PAM) — 现代 Linux 系统: pam_start("login", username, &conv, &pamh); // 启动 PAM pam_set_item(pamh, PAM_RHOST, hostname); // 设置远程主机 pam_set_item(pamh, PAM_TTY, tty); // 设置终端 // 认证循环(最多 RETRIES 次) while (true) { retcode = pam_authenticate(pamh, 0); // 验证密码 if (retcode == PAM_MAXTRIES) exit(0); // 超过最大尝试次数 if (retcode != PAM_SUCCESS) { // 记录到 /var/log/faillog failure(pwd->pw_uid, tty, &faillog); // 记录到 syslog SYSLOG(LOG_NOTICE, "FAILED LOGIN (%u)%s FOR '%s'", ...); } } // 账户有效期检查 pam_acct_mgmt(pamh, 0); // 检查账户是否过期 if (retcode == PAM_NEW_AUTHTOK_REQD) pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); // 强制改密 // 打开 PAM 会话 pam_open_session(pamh, hushed(pwd->pw_uid) ? PAM_SILENT : 0); setup_groups(pwd); // 设置辅助组 pam_setcred(pamh, PAM_ESTABLISH_CRED); // 设置凭证 传统路径(!USE_PAM) — 直接读取 /etc/passwd 和 /etc/shadow: while (true) { login_prompt(_("\n%s login: "), username, ...); // 显示登录提示 pwd = xgetpwnam(username); // 查询 passwd 文件 // 账户锁定检查:密码以 "!" 或 "*" 开头 if (user_passwd[0] == '!' || user_passwd[0] == '*') failed = true; // 如果是 shadow 用户,从 shadow 文件读取密码 if (strcmp(user_passwd, SHADOW_PASSWD_STRING) == 0) spwd = xgetspnam(username); // preauth (-f) 或密码验证 if (preauth_flag || pw_auth(user_passwd, username, reason, 0) == 0) goto auth_ok; // 访问控制:/etc/login.access if (!login_access(username, hostname)) failed = true; auth_ok: // 非控制台 root 登录记录 if (!failed && pwd->pw_uid == 0 && !is_console) SYSLOG(LOG_CRIT, "ILLEGAL ROOT LOGIN %s", fromhost); } 阶段四:会话建立 认证成功后: // PAM 路径:fork 后在子进程中 setuid if (getppid() == 1) { // 由 init 启动 setsid(); // 创建新会话 ioctl(0, TIOCSCTTY, 1); // 获取控制终端 } update_utmp(username, tty, hostname, utent); // 更新 utmp/utmpx // PAM 会话 pam_setcred(pamh, PAM_ESTABLISH_CRED); pam_open_session(pamh, 0); // 设置用户 ID setuid(pwd->pw_uid); chdir(pwd->pw_dir); // 切换到主目录 chown_tty(pwd); // 修改 tty 所有权 // 启动用户的 shell execle(pwd->pw_shell, pwd->pw_shell, "-", (char *)0, envp); --- 4. 关键辅助函数 ┌─────────────────┬──────────────────────────────────────────────────────┐ │ 函数 │ 作用 │ ├─────────────────┼──────────────────────────────────────────────────────┤ │ setup_tty() │ 配置终端参数(波特率、回显、擦除字符等) │ ├─────────────────┼──────────────────────────────────────────────────────┤ │ update_utmp() │ 写入 utmp/utmpx 记录(记录登录会话) │ ├─────────────────┼──────────────────────────────────────────────────────┤ │ check_nologin() │ 检查 /etc/nologin 或 NOLOGINS_FILE,阻止普通用户登录 │ ├─────────────────┼──────────────────────────────────────────────────────┤ │ dolastlog() │ 记录/读取 lastlog(最后登录时间) │ ├─────────────────┼──────────────────────────────────────────────────────┤ │ failure() │ 记录失败登录到 faillog │ ├─────────────────┼──────────────────────────────────────────────────────┤ │ chown_tty() │ 将 tty 设备所有权交给登录用户 │ ├─────────────────┼──────────────────────────────────────────────────────┤ │ setup_groups() │ 设置辅助组访问列表 │ ├─────────────────┼──────────────────────────────────────────────────────┤ │ get_pam_user() │ 从 PAM 获取用户名 │ └─────────────────┴──────────────────────────────────────────────────────┘ --- 5. 安全机制 1. 失败计数 — 登录失败次数记录到 /var/log/faillog,超过 LOGIN_RETRIES(默认 3 次)后锁定 2. 登录访问控制 — 通过 login_access() 查询 /etc/login.access 3. 终端时间限制 — porttime_check() 限制某终端的允许登录时间 4. root 登录限制 — 非控制台 root 登录记录为 ILLEGAL ROOT LOGIN 5. 会话超时 — LOGIN_TIMEOUT(默认 60 秒)内未完成登录则断开 6. 审计 — audit_log_acct_message() 将登录事件写入 audit 日志 --- 6. 依赖关系 login.c ├── pam_defs.h (USE_PAM) — PAM 认证接口 ├── defines.h — 通用宏定义 ├── faillog.h/failure.h — 失败日志 ├── getdef.h — 读取 login.defs 配置 ├── pwauth.h (非 USE_PAM) — 传统密码验证 ├── shadowlog.h — syslog 接口 └── prototypes.h — 函数原型声明 ✻ Sautéed for 1m 18s

接下来就可以非常详尽的针对这个仓库进行功能开发,代码理解,架构改善了。

总结

understand-anything这个skill让我们架构设计异常简单,非常适合程序员的一个skill神器。

参考

https://github.com/Lum1104/Understand-Anything