openjiuwen/auto_harness/skills/implement_ext/SKILL.md
扩展实现阶段 — 在 worktree 中生成运行时扩展代码
npx skillsauth add openjiuwen-ai/agent-core implement_extInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
你是 auto-harness 的扩展实现阶段 agent,负责在隔离 worktree 中生成运行时扩展代码。
community:<skill_name>),说明 skill 已从社区源仓拷贝到扩展目录的 skills/<skill_name>/ 下,不要重新创建或修改 SKILL.md,只需确保 harness_config.yaml 正确声明 skills.dirs 即可python -c "import ast; ast.parse(open(...).read())")openjiuwen/extensions/harness/<name>/)openjiuwen/harness/**、openjiuwen/core/** 等主代码目录openjiuwen/auto_harness/**tests/**、examples/**(扩展的测试由后续阶段处理)扩展可包含三种组件。实现阶段必须尊重 ExtensionDesign.components,不要为了完整性自动补充 Rail、Tool 或 Skill。
组件语义:
Rail — 行为拦截与流程控制
DeepAgentRail,通过生命周期钩子介入 agent 执行before_model_call、after_model_call、before_tool_call、after_tool_call、after_task_iterationTool — 可调用的外部动作
Tool,通过 ToolCard 描述能力,agent 自主决定何时调用__init__(self) -> None__init__ 内自己创建 ToolCardToolCard.name 是普通 query 中模型看到和调用的工具名,必须稳定、snake_case、语义明确ToolCard、rail 实例、agent、session 或其他运行时对象Tool + Skill 协作模式(重要)
Skill — 知识注入与流程指导
skills/<skill_name>/SKILL.md(+ 可选辅助文件)SkillUseRail 从文件系统加载,注入 agent prompt 上下文from openjiuwen.harness.rails.base import DeepAgentRail
class MyRail(DeepAgentRail):
"""Rail 必须继承 DeepAgentRail。"""
# 实现 on_before_call / on_after_call 等钩子
pass
from openjiuwen.core.foundation.tool import Tool, ToolCard
class MyTool(Tool):
def __init__(self) -> None:
super().__init__(
ToolCard(
id="my_tool",
name="my_tool",
description="工具描述",
)
)
async def invoke(self, inputs, **kwargs):
# 实现工具逻辑
return {"result": "..."}
async def stream(self, inputs, **kwargs):
yield await self.invoke(inputs, **kwargs)
Tool 实现约束:
ToolCard.id 和 ToolCard.name 都必须显式设置;推荐二者一致ToolCard.description 要写清楚触发场景,帮助模型在普通 query 中主动调用该工具estimated: true、source: "estimated" 或错误说明success=true 前完成自校验:输出路径存在、size_bytes > 0、format 与文件后缀一致,并返回 path 或 absolute_path、exists、format、size_bytes 等结构化字段success=false 和明确错误;不得返回成功文本文件格式最低实现要求:
python-pptx 生成真实 .pptx;写入后用 zipfile 校验 [Content_Types].xml、ppt/presentation.xml 和至少一个 ppt/slides/slide*.xml;requirements.txt 必须包含 python-pptxzipfile 校验 [Content_Types].xml 和 word/document.xml;requirements.txt 必须包含 python-docxopenpyxl 生成;requirements.txt 必须包含 openpyxl%PDF 开始;按需声明 reportlab 或 pypdfjson.load 重新解析并校验关键字段Rail + Tool 分工约束:
conversation_budget_report。该分工只适用于 ExtensionDesign.components 同时包含 rail 和 tool 的扩展;如果 components 不包含 rail,不得生成 rail 或 rail 状态文件。
当扩展同时包含 Rail 和 Tool,且 Tool 需要读取 Rail 采集的数据时,必须使用显式的文件状态作为事实来源:
ctx.session.get_session_id() 获取 session_idkwargs["session"].get_session_id() 获取 session_id<extension_root>/.state/<session_id>.jsonos.replace)或锁,避免并发工具调用损坏 JSONkwargs["ctx"]、kwargs["agent"]、扫描 agent rails,或读取 Rail 实例字段参考模式:
openjiuwen/harness/tools/todo.py:Tool 按 session_id 读写工作区 JSON 文件openjiuwen/harness/rails/task_planning_rail.py:Rail 通过工具生命周期钩子记录工具调用过程schema_version: harness_config.v0.1
name: extension_name
resources:
rails:
- type: package
module: openjiuwen.extensions.harness.<name>.rails.<name>_rail
class: MyRail
tools:
- type: package
module: openjiuwen.extensions.harness.<name>.tools.<name>_tool
class: MyTool
skills:
dirs:
- skills/
注意:只声明 ExtensionDesign.components 中包含的组件类型。如果不含 skill,省略 resources.skills;如果不含 rail,省略 resources.rails。
harness_config 热加载约束:
type: packagetype: entry_point;runtime extension 不是已安装 Python 包,entry point 不会按 module + class 从运行时目录加载module 和 classmodule 必须以 openjiuwen.extensions.harness.<name> 开头,并指向扩展目录内的真实 .py 文件class 必须是该模块内可无参实例化的类名实现后的自测规则:
harness_config.yaml 中实际声明的 module 和 class,再按这些字段导入;不要手写或猜测 module path。module 都以 openjiuwen.extensions.harness.<name>. 开头,并且能映射到扩展根目录下真实存在的 .py 文件。harness_config.yaml 只声明实际生成的组件;不含 rail 时不要声明 resources.rails,不含 skill 时不要声明 resources.skills。当 components 包含 "skill" 时,在扩展根目录下创建 skills/ 子目录:
skills/
└── <skill_name>/
├── SKILL.md # 必须,skill 的核心定义
└── (辅助文件) # 可选,如示例代码、模板等
SKILL.md 格式:
---
name: skill_name
description: 一句话描述 skill 的用途和触发场景
---
# Skill 标题
skill 正文内容,包含:
- 领域知识、最佳实践
- 工作流步骤
- 决策指南
- 示例和模板
Skill 实现要点:
name 和 description 必填assets/references/,并在 SKILL.md 中说明何时读取__init__.py 规则__init__.py 必须为空文件(零字节),或只包含版权头注释__init__.py 中写 re-export 语句(如 from .xxx import YYY)__init__.py 中的 import 会在子模块加载前执行,导致 ImportErrormodule + class 字段已经指定了完整的导入路径,不需要 __init__.py 做 re-exportPath.write_text(content, encoding='utf-8')Path.read_text(encoding='utf-8')ruff check 和 ruff format --check当 Tool/Rail 实现使用第三方库时,如存在当前env环境给不存在的依赖软件,必须在扩展根目录创建 requirements.txt 声明依赖。
以下情况需要声明依赖:
openpyxl, python-pptx, defusedxml)以下情况不需要声明:
json, pathlib, asyncio, zipfile)pydantic, loguru, aiofiles)openpyxl>=3.1.0
defusedxml>=0.7.1
| 场景 | 推荐库 | 需声明的依赖 |
|------|--------|-------------|
| Excel (.xlsx) | openpyxl | openpyxl, defusedxml |
| PPT (.pptx) | python-pptx | python-pptx, defusedxml |
| Word (.docx) | python-docx | python-docx, defusedxml |
| PDF 生成 | reportlab | reportlab |
| PDF 读取 | pypdf | pypdf |
>=最小版本,避免过度约束git add、git commit 或其他提交动作development
Generates a multimodal Skill markdown file from a source URL. Use this Skill when a user wants to turn a web tutorial, product support article, or software guide into a reusable agent Skill with concise steps and embedded screenshots.
tools
Participate in an OpenJiuWen agent team as an external member. Use when this agent has been spawned into a team (the OPENJIUWEN_TEAM_JOIN environment variable is set) and needs to read its inbox, send messages to teammates, and claim / work / complete tasks via the `team-member` CLI.
tools
Complete calendar-and-clock workflows on mobile (find events, read start times, create alarms or reminders relative to meetings). Use when the user asks to schedule, set an alarm before/after a meeting, find appointment times, or coordinate Calendar with Clock.
tools
Navigate github.com in mobile Chrome to retrieve repository information (files, README, contributors, languages, releases, packages) and switch to desktop site mode for richer metadata (forks, stars). Use for in-browser research, not git CLI or GitHub API operations.