agentsclimarketplace

Personal dev guard

Skill uvwt/agentdock/skill-sources/personal-dev-guard

Secure MCP runtime for AI agents to operate local machines, servers, and containers with multi-device orchestration.

Install
npx -y skills add uvwt/agentdock --skill personal-dev-guard

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

What its author says it does

Copied from the file, not written here

Use this skill before or during code changes and code review to enforce readable, restrained, maintainable code with low patch smell.

SKILL.md

23.3 KB, as published. Nobody here has run it

Personal Dev Guard / 个人开发守门规范

这是一个中文指令型 Skill。它的本体是这份 Markdown 文档,而不是自动评分脚本。

使用者读取本规范后,应按用户的个人高级开发标准进行代码开发和代码审查。这里的重点不是部署、排障、工具调用礼仪,也不是形式化流程检查,而是判断一份代码是否清晰、可读、克制、可维护,是否像高级开发者写出来的代码。

1. 短版核心规范

开发和审查代码时,优先遵守以下原则:

  1. 长期工程质量优先。不能只追求暂时能跑、暂时能实现、最小改动;方案必须符合项目既有规范,能长期维护、长期演进。
  2. 可读性优先。代码首先要能顺着读懂,主流程要连贯,不要让读者在一堆小函数之间来回跳转。
  3. 反对补丁味。不要为了修一个点硬塞特殊判断、flag、临时分支,让代码长期补丁化。
  4. 反对炫技抽象。抽象必须来自真实需求,不为了设计感、层级感、模式感而抽象。
  5. 项目规范优先。开发前要尊重现有目录结构、接口边界、命名风格、数据模型、错误处理、测试方式和发布约定;不要做一处可用、全局不一致的改动。
  6. 复杂度应该来自业务本身,而不是框架、helper、接口、目录层级或设计模式额外放大出来的复杂度。
  7. 核心流程需要中文注释。注释重点解释为什么、业务原因、设计取舍、坑点和非显然约束。
  8. 测试应该覆盖真实风险,并且测试代码本身也要可读,像业务行为文档,而不是复杂 mock 工程。
  9. Go 项目优先简单直接:少做 Java 式机械分层,不提前定义 interface,不为了 mock 污染业务结构。
  10. 泛型默认克制使用:能用普通函数、明确类型或具体结构表达清楚的,就不要上泛型;只有真实多类型复用能明显减少重复并保持可读时才使用。
  11. any 不算泛型,但也要克制:边界层解析动态 JSON 可以用,业务内部优先转成明确 struct、具体类型或小结构,避免把字段契约藏进运行时。
  12. Review 时优先看:是否符合长期规范性和项目规范,主流程是否连贯,有没有补丁味和炫技抽象,测试/验证是否覆盖风险,改动范围是否形成完整闭环。
  13. 包和目录按稳定职责与共同变更原因组织;既不要为了架构感机械拆包,也不要把多个独立能力长期堆进一个大包或 God Object。

如果因为现实约束违反核心偏好,必须在 Review 或交付说明中说清楚:为什么违反、替代方案是什么、风险是什么、后续是否需要修正。

2. 规范定位

本规范约束的是代码开发质量,不是 AgentDock 运维流程。

它应该用于:

  • 新增功能、修复 bug、重构、清理代码。
  • Go 项目开发,尤其是服务端、CLI、工具类项目。
  • 其他语言项目中的通用可读性、可维护性和测试判断。
  • 开发后的代码 Review 和 debrief。

它不重点覆盖:

  • Docker 部署、反代、证书、服务排障。
  • iOS/watchOS 安装签名流程。
  • 工具调用前后如何汇报的细节。
  • 自动化评分、静态分析或代替测试工具。

这份规范不是要求所有代码都写成一种形状,而是帮助开发者始终回答一个问题:未来接手这段代码的人,能不能顺着读懂、放心修改、快速定位问题?

当“最小改动”和“长期正确”冲突时,不能默认选择最小改动。应该优先选择符合项目规范、能形成完整闭环、未来维护成本更低的方案;如果只能先临时处理,必须说明临时性、风险和后续正式方案。

3. 高级开发者判断标准

高级开发者不是把代码写得复杂,而是把真实复杂度控制在可读、可定位、可维护的范围里。

优先级如下:

  1. 主流程可读,读者能顺着理解业务链路。
  2. 方案符合项目既有规范和长期演进方向,不为了暂时可用破坏一致性。
  3. 代码没有明显补丁味、临时味和硬塞特例。
  4. 抽象克制,不为了看起来高级而制造层级。
  5. 错误路径、边界条件和状态变化清楚可见。
  6. 测试或验证覆盖本次改动真正的风险。
  7. 改动范围服务当前目标,同时足以把功能、数据、接口、前端、测试和文档等相关闭环补齐。

不高级的代码通常有这些味道:

  • 为了短函数把主流程拆散,读代码需要频繁跳转。
  • 为了一个小需求引入过多 interface、manager、processor、adapter、factory。
  • 为了快速修复硬塞特殊 case,没有说明原因、影响和退出条件。
  • 错误被吞掉、被模糊包装,或者只打印日志后继续。
  • 业务对象含义不清,充斥 map、any、万能 DTO、泛名 helper。
  • 测试比业务代码还难读,mock 和 fixture 成为新的复杂度来源。
  • 为了快或“少改点”,只修表面现象,不处理同一业务链路里的规范、一致性和闭环问题。

4. 主流程与函数组织

主流程优先连贯。能在一个函数或一段清楚代码里顺着读懂的业务链路,不要为了形式上的“短函数”拆成一堆独立小方法。

允许拆分,但拆分必须服务于可读性,而不是破坏可读性。合理拆分的理由包括:

  • 多处真实复用。
  • 隔离明确副作用,例如外部请求、数据库读写、文件操作。
  • 隐藏局部复杂细节,让主流程更容易读。
  • 形成清晰测试边界。
  • 表达稳定的业务概念。

不接受的拆分理由包括:

  • “这个函数太长,所以必须拆”。
  • “高级项目都这样分层”。
  • “以后可能会复用”。
  • “这样看起来更架构化”。
  • “为了套某个设计模式”。

如果确实拆分,入口或主流程仍然应该像目录一样清楚展示完整业务顺序。读者不应该为了理解主线,在多个 helper 里来回跳转。

坏例子:主流程被拆碎

func UpdateUser(ctx context.Context, req UpdateUserRequest) error {
    user, err := loadUser(ctx, req)
    if err != nil {
        return err
    }
    prepareUser(user)
    applyRequest(user, req)
    normalizeUser(user)
    fillAuditFields(user)
    return saveUser(ctx, user)
}

这段代码的问题不是函数短,而是读者必须跳进多个 helper 才知道用户到底被改了什么。

好例子:主流程可见,局部复杂再封装

func UpdateUser(ctx context.Context, req UpdateUserRequest) error {
    if req.UserID == "" {
        return fmt.Errorf("用户 ID 不能为空")
    }

    user, err := repo.FindUser(ctx, req.UserID)
    if err != nil {
        return fmt.Errorf("查询用户失败: %w", err)
    }

    // 核心字段变更保持在主流程中,方便读者直接看到本次更新会影响什么。
    user.Name = strings.TrimSpace(req.Name)
    user.Email = strings.ToLower(strings.TrimSpace(req.Email))
    user.UpdatedAt = clock.Now()

    if err := validateUserForUpdate(user); err != nil {
        return err
    }
    return repo.SaveUser(ctx, user)
}

这里不是禁止 helper,而是把关键业务变化留在主流程里,让读者能顺着读懂。

5. 可读性与复杂度控制

代码不追求短,也不追求抽象,追求业务复杂度本身可见、可读、可定位。

要求:

  • 可读性不是把代码拆碎,而是让业务判断、状态变化、错误路径清楚呈现。
  • 不为了“统一架构”“短函数”“设计模式”把简单问题复杂化。
  • 复杂逻辑可以存在,但必须让读者能顺着主线理解。
  • 重要数据从哪里来、在哪里变、最后怎么用,应该能追踪。
  • 重要字段的修改尽量直接出现在主流程中。
  • 不要让很多 helper 在深处偷偷修改同一个对象。
  • 如果 helper 会修改对象,函数名和中文注释必须说清楚它会改什么、为什么改。

判断一段代码是否可读,可以问:

  • 我能否不跳很多文件就理解主流程?
  • 我能否看出关键字段在哪里被修改?
  • 我能否看出失败时会怎么返回?
  • 我能否看出哪些逻辑是业务规则,哪些只是技术细节?
  • 如果半年后再看,我是否还能快速定位改动点?

6. 抽象与模块边界

不反对抽象,但抽象必须来自真实需求。

允许抽象的理由:

  • 多处真实复用。
  • 隔离明确变化点。
  • 降低当前阅读复杂度。
  • 表达稳定领域概念。
  • 形成清晰测试边界。
  • 隔离外部系统、网络、数据库、文件系统等边界。

不接受的理由:

  • “以后可能会用”。
  • “这样看起来更高级”。
  • “高级项目都这么分层”。
  • “为了套设计模式”。
  • “为了 mock 所以先定义接口”。

接口、抽象层、目录结构都应该减少理解成本,而不是制造跳转成本。

7. Go 项目偏好

Go 项目优先简单直接,尊重 Go 的工程习惯,不做 Java 式机械分层。

偏好:

  • 包结构优先简单,不为了架构感拆很多目录。
  • handler、service、repository 可以存在,但必须来自真实职责边界,不机械套模板。
  • interface 不要提前定义;只有多实现、测试替身、外部边界隔离、依赖反转确实需要时才定义。
  • 泛型不要提前使用;只有同一逻辑确实服务多种具体类型、普通函数会产生明显重复,并且泛型版本仍然容易读懂时才使用。
  • 能用具体类型、简单结构体、普通函数或小范围重复表达清楚的,优先不用泛型;不要为了“通用”“优雅”把数据流和错误流藏进类型参数里。
  • 如果使用泛型,类型参数数量要少,约束要直白,调用点要比非泛型方案更清楚;否则退回具体实现。
  • any 不是泛型,但同样不要随手使用;除非处在 MCP/HTTP/JSON/插件 manifest 这类动态边界,业务逻辑内部优先使用明确 struct、具体字段和具体类型。
  • 动态边界可以先用 map[string]any 接住外部输入,但进入核心流程前应尽快校验并转成明确 request struct;不要让 any 和字符串 key 在业务链路里到处传。
  • 不要用 any、万能 DTO 或 map[string]any 伪装通用性;字段契约如果对维护者重要,就应该让类型、命名或局部结构直接表达出来。
  • 不要为了 mock 而污染业务代码结构。
  • Go 代码优先清晰数据流、错误流、调用流,而不是层级数量。
  • 错误处理保持显式直接,避免把关键失败路径藏在深层 helper 中。
  • 表格测试可以使用,但不要为了表格测试牺牲测试场景的可读性。
  • 小型项目或工具项目不需要强行套大型服务端分层。

Go 里的 interface 应该由消费方在真实需要时定义,而不是在实现方提前制造抽象。

8. 包与目录组织

包应围绕稳定职责和共同变更原因组织,而不是单纯追求目录少、文件少或层级少。

要求:

  • 一个包应该能用一句明确的话说明职责。只能用“负责各种工具”“处理通用逻辑”“管理所有运行能力”描述的包,通常已经过宽。
  • 文件数量和代码行数不是强制拆包标准,但属于结构审查信号。生产文件明显过多、代码规模持续增长、出现多个互不相关的功能前缀,或者不同需求长期修改同一个 Runtime、Manager、Registry 时,必须检查包是否已经失去内聚性。
  • 包优先按业务能力、外部边界或共同变更原因拆分,不按 handler、service、repository 等技术层机械横切,也不采用一文件一包、一工具一包。
  • 组合根只负责依赖创建、生命周期、注册和调用分发,不应继续承载文件处理、网络调用、数据转换等具体业务实现。
  • 当一个结构体持有多个彼此独立的子系统依赖,并且大量方法只使用其中一两个依赖时,应检查它是否已经成为 God Object,并考虑按能力拆成具体服务。
  • 拆包优先抽取职责完整、依赖方向清楚的模块。相关类型、输入输出契约、错误转换和测试应随职责一起迁移,避免只移动部分文件形成半拆分状态。
  • 新增功能前先判断它属于现有包的稳定职责,还是暴露了新的模块边界;不得因为已有包方便访问内部变量,就默认继续向其中堆代码。
  • 禁止为了减少当前包文件数,把代码转移到 common、utils、helpers 等无明确职责的垃圾包。
  • 包之间的依赖方向必须清楚,具体能力不应反向依赖组合根;不要为了拆包制造循环依赖,再用全局变量、回调或空泛 interface 掩盖。
  • 拆包后仍应保持调用主线清楚。目录层级和接口数量必须减少理解成本,不能只是把一个大包变成多个相互跳转的小包。

判断是否需要拆包,可以问:

  • 这些文件是否服务同一个稳定职责,并且通常因同一类需求一起变化?
  • 新增一个独立能力时,是否总要修改同一个大 Runtime、注册表或 Schema switch?
  • 测试是否已经混合多个互不相关的业务场景,难以按能力定位?
  • 抽出该能力后,依赖是否会变得更单向、更少,而不是增加更多桥接层?

拆包的目标是提高内聚、降低耦合和缩小变更影响面,不是让目录树看起来更“专业”。

9. 命名规范

命名优先服务阅读,让读者快速理解“这是什么、为什么存在、在业务里代表什么”。

要求:

  • 命名直白,不炫技,不滥用缩写,不追求抽象感。
  • 核心变量、函数、结构体命名必须表达业务意图。
  • 短生命周期局部变量可以简短,但不能牺牲理解。
  • 不要用 Manager、Processor、Helper、Util、Common 这类泛名掩盖真实职责。
  • 不要为了显得通用,把具体业务名改成空泛概念。
  • 布尔变量要能读出判断语义,例如 canSyncshouldRetryhasPermission

一个名字如果需要读实现才能知道它代表什么,通常就不够好。

10. 中文注释规范

注释默认使用中文,方便长期维护和快速理解。

要求:

  • 不写无意义注释,不重复代码表面行为。
  • 注释重点解释“为什么这么做”,而不是机械解释“这行做了什么”。
  • 核心代码流程需要有适度中文注释,让读者快速把握主线。
  • 复杂业务规则、历史原因、边界条件、兼容逻辑、非显然取舍必须注释。
  • 如果某段代码必须保留看似奇怪的判断,必须用中文说明原因。
  • TODO、workaround、临时兼容逻辑必须中文说明原因、影响范围、退出条件和后续正式方案。

好的注释应该降低未来阅读成本,不应该替代糟糕命名和糟糕结构。

11. 临时方案与补丁味

允许现实中的临时处理,但必须说明清楚,不能伪装成正式设计。

要求:

  • 不鼓励 TODO、workaround、临时兼容分支泛滥。
  • 如果确实需要临时处理,必须用中文注释说明为什么现在必须这样做。
  • 必须说明影响范围、什么时候可以删除、后续正式方案是什么。
  • 临时方案不能伪装成长期架构。
  • 不能为了快而把特殊 case 硬塞进主流程,导致代码长期补丁化。
  • 不能把“最小改动”“先能用”当成唯一理由,留下明显不符合项目规范的半成品。
  • 临时方案如果会影响数据结构、接口契约、用户体验或后续维护,必须同步给出长期收敛路径。

临时处理如果没有退出条件,就很容易变成永久技术债。

12. 错误处理与边界条件

错误路径要和正常路径一样容易读懂。

要求:

  • 错误处理必须显式、直接。
  • 关键失败路径不能藏在很深的 helper 里。
  • 边界条件尽量靠近主流程,让读者能看到什么时候失败、为什么失败、失败后怎么返回。
  • 不吞错误,不返回模糊错误,不只打印日志然后继续。
  • Go 代码里的错误包装要服务于定位问题,而不是制造一层层无意义包装。
  • 日志和错误信息要提供定位上下文,但不能泄露隐私信息或敏感配置。

失败路径如果读不懂,代码就不可靠。

13. 依赖、框架与并发克制

高级开发不是引入更多依赖和框架,而是知道什么时候不引入。

要求:

  • 小问题不要引入大依赖。
  • Go 项目优先标准库和简单实现。
  • 新依赖必须有明确收益:减少复杂度、提升可靠性、解决真实问题。
  • 不为了标准化引入复杂框架。
  • 没有证据不要提前引入缓存、goroutine、channel、锁或复杂并发结构。
  • 并发代码必须有清楚的生命周期、取消机制、错误处理和资源释放。
  • 性能优化要说明瓶颈和验证方式,不做无证据优化。

并发和缓存不是高级感来源,清楚可靠才是。

14. 测试规范

该测的一定测;不适合自动化测试的,必须给出替代验证和理由。

优先测试:

  • 核心业务分支。
  • 状态变化。
  • 错误路径。
  • 边界条件。
  • 兼容逻辑。
  • 曾经出过 bug 的路径。

测试代码本身也必须可读:

  • 测试要表达业务场景,不要只围绕实现细节写。
  • 测试用例命名要直白,能看出“什么条件下,期望什么结果”。
  • 不要堆复杂 helper、fixture、mock,让测试比业务代码还难懂。
  • 能用真实小对象、内存实现、表格测试表达清楚的,不要上复杂 mock 框架。
  • 测试失败信息要能帮助定位问题,而不是只告诉人失败了。
  • 不要为了测试把业务代码改得更丑。

测试不是为了覆盖率数字,而是为了覆盖这次改动真正的风险。

15. 改动范围克制

改动必须服务当前目标,不做无关美化和范围膨胀;但“克制”不等于只做最小改动,更不等于留下长期不一致。

要求:

  • 不顺手重构无关代码。
  • 不为了适配个人风格大面积改现有项目结构。
  • 可以顺手改善明显问题,但必须和当前目标直接相关。
  • 必须补齐当前目标涉及的真实闭环,不能只改一个点却让接口、状态、UI、数据或测试处于不一致状态。
  • 不借一个小需求重写一大片代码。
  • 如果确实需要扩大范围,必须说明原因、收益和风险。
  • 删除代码前要确认没有真实调用方或保留兼容路径。

简化比新增抽象更优先,但简化也必须有边界。

如果为长期规范性需要扩大改动范围,应明确说明扩大范围的必要性、涉及面、验证方式和剩余风险,而不是假装这是一个“小修”。

16. Review 检查标准

Review 时按以下优先级判断:

  1. 方案是否符合项目既有规范、长期可维护性和长期演进方向。
  2. 代码能不能顺着读懂,主流程是否连贯。
  3. 有没有补丁味、临时味、炫技抽象、机械分层。
  4. 测试或验证是否覆盖这次改动真正的风险。
  5. 改动范围是否既克制又完整,有没有只图最小改动导致闭环缺失。

Review 必问:

  • 这份代码是否符合项目规范,能不能长期维护?
  • 这份代码像不像高级开发者写的?
  • 主流程能否不用频繁跳转就读懂?
  • 业务概念是否清楚?
  • 重要数据变化是否可追踪?
  • 错误路径和边界条件是否容易理解?
  • 是否有临时补丁伪装成正式设计?
  • 是否为了暂时可用或最小改动,牺牲了数据、接口、前端、测试或文档的一致性?
  • 是否为了架构感引入了不必要的抽象?
  • 是否用了不必要的泛型?能否用具体类型或普通函数更清楚地表达?
  • 是否用了不必要的 any / map[string]any?这些动态值是否只停留在边界层,进入核心流程前是否转成了明确结构?
  • Go 代码是否保持简单直接?
  • 包是否围绕稳定职责保持内聚?是否出现多个独立能力堆在同一包、组合根承载具体实现或 God Object 持有过多子系统的问题?
  • 如果进行了拆包,边界是否来自真实职责,依赖方向是否清楚,是否避免了一工具一包、机械分层和 common/utils 垃圾包?
  • 中文注释是否覆盖核心流程、坑点和非显然取舍?
  • 测试是否覆盖真实风险,而不是只覆盖实现细节?
  • 未来的人接手会不会骂人?

如果违反核心偏好,Review 必须说明:违反了哪条、为什么必须这样做、风险是什么、后续是否需要修正。

17. 关键示例

示例一:不要机械 interface

坏例子:

type UserServiceInterface interface {
    UpdateUser(ctx context.Context, req UpdateUserRequest) error
}

type UserServiceImpl struct {
    repo UserRepositoryInterface
}

如果当前只有一个实现,没有外部边界,也没有真实替身需求,这种 interface 只是增加跳转。

好例子:

type UserService struct {
    repo *UserRepository
}

等出现真实边界时,再在消费方定义需要的 interface。

示例二:临时方案必须中文说明

坏例子:

if user.ID == "legacy" {
    return nil
}

好例子:

// 兼容 2024 年旧导入任务产生的 legacy 用户记录。
// 这类记录没有完整资料,当前只跳过同步,避免阻断正常用户更新。
// 旧数据迁移完成后可删除该分支,迁移任务见 internal/migrate/legacy_users.go。
if user.ID == "legacy" {
    return nil
}

示例三:测试像业务行为文档

坏例子:

func TestUpdate(t *testing.T) {
    mock := newComplexMockFactory().WithA().WithB().Build()
    got := run(mock)
    assert.Equal(t, true, got)
}

好例子:

func TestUpdateUser_邮箱为空时返回错误(t *testing.T) {
    req := UpdateUserRequest{UserID: "u1", Email: ""}

    err := service.UpdateUser(context.Background(), req)

    if err == nil || !strings.Contains(err.Error(), "邮箱不能为空") {
        t.Fatalf("期望返回邮箱为空错误,实际: %v", err)
    }
}

测试名称和断言直接表达业务行为,失败时也能定位原因。

18. 给 Agent 的执行要求

当你读取本 Skill 后,应将它作为用户的个人代码开发标准执行。

要求:

  • 不要把本规范降级成泛泛建议。
  • 开始改代码前先理解项目现有规范:目录结构、接口契约、数据模型、命名风格、错误处理、测试方式、部署/发布约定;不要凭空另起一套。
  • 开发或 Review 前检查相关包的职责和变更热点;既要防止机械拆分,也不能因为“Go 包结构优先简单”而忽略已经失去内聚性的大包。
  • 写代码时优先保证长期规范性、长期可维护、主流程连贯、中文注释清楚、抽象克制、测试可读。
  • 不能只图暂时可用、暂时可实现或最小改动;当最小改动会破坏长期一致性时,应选择能形成项目闭环的方案。
  • Review 或总结时不要只说“已完成”,要指出改动是否符合本规范中的关键标准,尤其是项目规范、长期维护性和闭环完整性。
  • 如果代码为了现实限制没有完全符合规范,必须明确说明原因、风险、替代方案和后续处理方式。
  • 不要把部署、排障、工具调用规范混入本 Skill 的核心判断,除非用户另行要求。

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.