Community编程与开发github.com

EugineKosenko/majordom – 创建新组件(literate org-babel Rust 风格)

在 org-babel 文学化 Rust 项目(如 ads-back、ads-front)中快速搭建新组件、命令、Crate 或 CLI 子命令,遵循声明在先、定义在后、每个关注点一个标题的既定模式。

majordom – 创建新组件(literate org-babel Rust 风格) 是什么?

该技能(SKILL.md)为 Claude Code 等 AI 代理提供了一套严格但灵活的流程,用于在采用文学化编程(literate programming)风格的 Rust 项目中添加新代码组件。它支持四种主要变体:在现有 Crate 中添加过程/命令(变体 A)、为现有 CLI 添加子命令(变体 B)、添加 Yew 前端组件(变体 C)、以及创建全新的工作空间 Crate(变体 D)。其核心原则包括:根据相邻文件的语言来确定新文件的语言(英语或乌克兰语);每个组件对应一个独立的 `.org` 文件,包含一个“骨架”`#+begin_src` 代码块;遵循 `noweb` 块组织模式(先声明后定义);以及每个逻辑步骤使用独立的标题(如 `* Виконавець`/ `* Дії`)。对于变体 D,该技能会引导用户创建 `config.org`、`env.org` 和 `main.org`,并将新 Crate 注册到工作区级别的 `config.org` 中。每次编辑后,它强制要求通过 `emacsclient` 进行 `org-babel-tangle` 导出、`cargo check` 零警告验证、对 .org 文件运行 `org-lint`,并对散文内容进行 `org-fill-paragraph`。该技能设计用于 `ads-back`、`ads-front` 及其类似项目,并记录在 `~/.claude/CLAUDE.md` 中。

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/EugineKosenko/majordom/tree/HEAD/skills/create-cmpnnt

Installed? Explore more 编程与开发 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

创建组件 (create-cmpnnt)

用于在文学化 org-babel 风格项目中创建新组件(cmpnnt)——命令、过程、子命令、Yew 组件或整个 crate。该模式基于 ~/.claude/CLAUDE.md 中的文档,并取材自 code/ads-back 的实际文件(crates/api/create-card.org、crates/api/retrve-card.org、crates/cli/main.org、crates/svc/main.org、根目录下的 config.org、env.org)。

第 0 步 — 确定变体

默认情况下(无显式参数),从用户请求本身确定变体;如果存在歧义,通过 AskUserQuestion 提问澄清,而非默默猜测:

  • A. 在现有 Crate 中添加过程/命令 —— 典型情况(例如在 crates/api 中添加新的 rocket 处理器,或在 crates/db 中添加库函数)。创建一个新的 .org 文件,config.org 不变。
  • B. 为现有 CLI 添加子命令 —— 新文件 <子命令>.org(模块)+ 插入到该 Crate 现有 main.org 文件中(mod、Command:Елементи、Варіанти)。
  • C. Yew 组件(ads-front)—— 结构更接近 crates/app/marker.org:包含一个“属性”部分(带有组件属性)和 Html 块。使用相同的骨架(声明在定义之前,每个概念一个标题),但块术语不同。
  • D. 新 Crate(“联邦 cargo”)—— 当组件逻辑上不属于任何现有 Crate 时。此时,除了组件本身,还需要创建新 Crate 的 config.org、env.org、main.org,并将其注册到根目录 config.org 中(参见第 4 步)。

不要“以防万一”指定变体 D —— 仅当用户显式要求新 Crate,或者现有 Crate 在逻辑上都不合适(且经用户确认)时使用。

第 1 步 — .org 文件的语言

语言取决于具体情况,而非固定不变。在创建文件之前,检查目标目录中相邻 .org 文件的语言(code/ads-back/env.org 为英语,大多数 crates/api/*.org 为乌克兰语):如果目录具有明显的语言多数,则使用该语言编写;如果这是一个新目录或相邻文件的语言不明确,则向用户提出一个问题,不要猜测。

第 2 步 — 公共骨架(所有变体)

无论变体如何,每个具有自身 :tangle 目标的新 .org 文件:

  1. #+title: ... — 组件名称(使用第 1 步中确定的语言)。

  2. 如有必要,添加一个引用规范文档的段落([[https://...][规范]]),如 create-card.org 中所示。

  3. 第一个标题(* 模块 / * 文件 / * Crate — 名称仿照同一目录中相邻文件的示例,并非严格固定),包含一个骨架代码块:

    #+begin_src rust :noweb yes :mkdirp yes :tangle src/文件名.rs
      <<声明>>
    
      <<定义>>
    #+end_src
    
  4. 骨架之后立即紧跟 * 执行者 部分(用于过程/命令),包含两个代码块::noweb-ref 声明(引入,包括来自 ads_api 的类型 Request/Response)和 :noweb-ref 定义(函数 pub fn run(...) 本身,其主体主要包含 <<动作>>,如果需要事务,则位于 db::cnnctn().transaction(...) 内部)。

  5. 每个后续的逻辑细节(检查、获取字段、插入表等)作为一个独立的 */** 标题,具有自身的 :noweb-ref 声明(如果需要新的 use)和 :noweb-ref 动作——按此顺序(声明在使用之前,与所有其他地方一致)。不要将所有逻辑收集到一个块中——每个有意义的步骤都应有一个标题,如 create-card.org 所示(那里有 15 个以上的独立标题用于一个过程)。

  6. 如果一个步骤产生了一个辅助函数(例如 create-card.org 中的 upsert_phone)——使用独立的 :noweb-ref 定义 用于函数签名,其主体通过一个命名的 noweb-ref(upsert-phone:动作),以及 **/*** 子标题用于其内部的每个动作。

变体 B(CLI 子命令)的不同之处在于不创建新的骨架代码块;相反,将三个 noweb 块添加到现有的 main.org 中,无需新的骨架标题::noweb-ref 声明(mod 新子命令;)、:noweb-sep ",\n" :noweb-ref Command:Елементи(带参数字段的 Command 枚举变体),以及 :noweb yes :noweb-sep ",\n" :noweb-ref 变体(Command::变体 { ... } => crate::模块::run(...))——每个块位于自己的 * 标题下,标题按操作命名(例如 * 创建组织),实现本身位于一个按照公共骨架(第 2 步,变体 A)创建的单独新子命令 .org 文件中。

变体 C(Yew 组件)在部分名称上有所不同:用“属性”部分(struct ...Props,一个属性 = 一个 ** 子部分,:noweb-sep ",\n" :noweb-ref 名称Props:Властивості)和“组件”部分(#[function_component(...)],主体为 <<名称:Стан>>、<<名称:Ефекти>>、<<名称:Обробники>>、html! { <<名称:Html>> })替代“执行者”。请参考 code/ads-front/crates/app/marker.org 作为此变体的实际示例。

第 3 步 — 典型的 main 函数(变体 D,初始版本)

新 Crate 的第一个版本的 main.org 应该尽可能简单——没有错误处理、没有 Result、没有 async、没有 logger/env 初始化,除非有具体需求:

#+title: CRATE 名称

* 文件

#+begin_src rust :noweb yes :mkdirp yes :tangle src/main.rs
  <<声明>>

  <<定义>>

  fn main() {
      <<动作>>
  }
#+end_src

<<动作>> 最初可能完全为空(新 Crate 尚未做任何事情)——这是一个正常的第一步,后续的标题将逐步填充它,就像 crates/cli/main.org/crates/svc/main.org 中那样。错误处理(Result、?)、async、dotenv/env_logger 的初始化等应通过单独的标题稍后添加,只有当特定步骤实际需要时才添加——不要预先添加。

第 4 步 — 新 Crate:config.org 和在联邦 config.org 中的注册

  1. crates/名称/config.org — Crate 文件(参见 crates/cli/config.org 作为示例):

    #+title: =Cargo= 文件
    
    * 文件
    
    #+begin_src toml :noweb yes :tangle Cargo.toml
      [package]
      name = "名称"
      version = "0.1.0"
      edition = "2021"
    
      [dependencies]
      <<依赖>>
    #+end_src
    

    每个依赖项作为一个独立的 * =crate 名称= 标题,带有 :noweb-ref 依赖(名称 = { workspace = true }),按照 CLAUDE.md 中的规则排序(第三方 → forge → 项目内 crate,否则按字母顺序)。* 版本 =Rust=/* 本地配置(rust-toolchain.toml/.cargo/config.toml)仅当该目录中的其他 crate 已经这样做时才从相邻的 config.org 复制——不要“以防万一”添加它们,如果相邻的 crate 都没有这样做。如果复制,文件将成为多目标文件(多个不同的 :tangle),因此所有 noweb 块(包括 依赖)都应使用前缀名称(Cargo:依赖、config:定义 等,参见 CLAUDE.md)——就像根目录的 config.org 中那样。

  2. 在根目录 config.org(工作区)中,仿照根目录中 * =db=/* =api= 部分的示例,添加一个新的 * =名称= 标题,包含两个代码块:

    #+begin_src toml :noweb-sep ",\n" :noweb-ref Cargo:工作区成员
      "crates/名称"
    #+end_src
    
    #+begin_src toml :noweb-ref Cargo:依赖
      名称 = { path = "crates/名称" }
    #+end_src
    
  3. env.org — 如果新 Crate 没有引入自己的环境变量,则无需修改。如果引入了,并且项目中已经存在一个公共的根目录 env.org,则将一个新的 * 部分(带有自身的 :noweb-ref,如 * 数据库访问/* =JWT= 参数)添加到该文件中,而不是创建一个单独的文件。仅当新 Crate 是一个独立的部署(拥有自己的 .env,而不是同一个进程)并且没有公共的 env.org 时,才为它单独创建 env.org。无论如何,第一个 env.org 可以完全没有具体的变量(可以完全没有值,只有主文件)——只是一个骨架:

    #+title: =dotenv= 文件
    
    * 配置文件
    
    #+begin_src conf :noweb yes :tangle .env.example
      <<定义>>
    #+end_src
    

    稍后有实际变量出现时,再填充具体的 * =X= 参数 部分。

第 5 步 — 每次更改后验证

在对 .org 源文件进行每次实质性编辑后:

  1. 通过 emacsclient --eval 进行实际的 tangle 导出(切勿手动编写 .rs/.toml/.env.example 的内容 —— 参见相关的全局规则)。
  2. 运行 cargo check -p CRATE(对于 ads-front,添加 --target wasm32-unknown-unknown) — 零警告和错误。
  3. 对更改后的文件运行 org-lint 技能,并立即修复已确认的问题;对于“需要检查”的问题进行审查。
  4. 对于新编写或已更改的散文内容,通过相同的 emacsclient 运行 (font-lock-ensure) + org-fill-paragraph,不要手动调整。

在针对每个新更改或已更改的 .org 文件完成上述四个要点之前,不要向用户展示该组件为就绪状态。

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

EugineKosenko/majordom

Analyse a Figma .fig file kept in a project's spcfctn/ui/draft. Unpacks and decodes it offline (kiwi), breaks it into sections, screens, text rows and rasters, writes the analysis to spcfctn/ui/*.md, then fetches the author's comments through the figma MCP by link, binds them to screens by geometry, checks that the comments agree with the content of the file and asks the user to clarify what does not. Use when the user asks to analyse, decode or re-read a .fig file or Figma wireframes, or to refresh spcfctn/ui after a new export.

EugineKosenko/majordom

Керування сесіями claude-code-ide.el у живому Emacs через emacsclient headless — старт/continue/resume без блокуючих запитів, безпечна зупинка, перемикання permission-mode і auto-accept, навігація в інтерактивних picker'ах. Використовуй, коли сесія "Мажордом" має підняти, продовжити, зупинити чи інспектувати сесію claude-code-ide для іншого проєкту.

EugineKosenko/majordom

Bootstrap a new project in this user's standard layout — .claude-root, .dir-locals.el (root: org-link abbreviation), code/, spcfctn/code/ (with its own git repository) and a .claude/ directory with its own git repository and a CLAUDE.md that fixes the project's prose language and its short two-letter project code (chosen by the user from options the agent proposes) — and translate any files already present into that language. Use whenever the user asks to create, start, set up, initialise or "оформити" a new project (or to bring an existing bare directory to the standard layout).

EugineKosenko/majordom

Check org/md prose in this user's projects against the prose-formatting conventions in ~/.claude/rules/org-babel.md (~...~ vs =...= markup, acronym casing, /.../ glossary terms, real org-links vs italics/plain text, spaces around / between two markups, trailing newline, fill-column). Use proactively right after editing prose paragraphs in an .org or .md file (in place of manually re-deriving each rule from memory), and whenever the user explicitly asks to check/lint org rules or compares the request to running clippy.

相关技能