diy-harness(dh)
自研 agent harness:运行时自己实现(agent loop、工具、后端、中间件), instructions 沿用 Deep Agents(系统提示词、工具描述、中间件段落、子 agent 提示词、工作流)。
设计文档在 docs/overview.md。当前进度:M0–M9 全部收口,
M10 把包发上 PyPI(里程碑状态与证据见
docs/overview.md §11 和
TASKS.md)。
仓库:https://github.com/zxu756/diy-harness;项目约定见 AGENTS.md
(每次任务都要跑测试、lint、快照校验,然后 commit + push)。
开发
uv sync # 安装依赖(Python 3.12)
uv run pytest # 单元测试(不需要 API key)
uv run ruff check . # lint
uv run python scripts/sync_prompts.py --check # 校验提示词快照与固定 commit 一致
bash scripts/ci_sim.sh # 本地把 CI 的 check job 跑一遍(沙箱 HOME + CI 终端环境)
改打包 / 依赖后再跑一条 uv run python scripts/check_wheel.py(uv build 出 sdist + wheel,干净 venv 里两种产物各装一遍 → 读提示词 + dh debug prompt)。
这三条也是 CI 门(.github/workflows/ci.yml):push / PR 自动跑;
快照校验那步会先把上游固定 commit 拉到 ~/deepagents(只拉那一个 commit)。
dh eval --split holdout --json 放在手动触发里(要 OPENCODE_API_KEY,没配就跳过)。
安装(让 dh 在任何目录都能用)
uv tool install diy-harness # 从 PyPI 装(0.1.0 起;`pipx install diy-harness` 同效)
uv tool install --editable . # 本地开发:装当前源码(改代码立即生效,`dh evolve` 用这条)
cp .env ~/.diy-harness/.env # 可选:把 key 放全局位置,任意目录都能直接聊(chmod 600)
dh --version # 任意目录都能敲
- 为什么用
--editable:dh会跑当前源码(自改循环dh evolve --repo .改完立刻就生效), 不用重装。改了依赖(pyproject.toml)后重跑一次这条命令即可;uv tool list看装了哪些。 - key 的查找顺序:环境变量 →
./.env→~/.diy-harness/.env。放全局那份之后, 在任何项目目录敲dh都能直接开始(项目自己的./.env可以覆盖它)。 - 不想要 editable 也行:
uv tool install .(或从 PyPI 装)装普通 wheel 一样能用 —— 构建钩子会把prompts/复制进包里(diy_harness/_prompts/),prompts.py运行时优先读这份包内副本,找不到才回退仓库根。 改打包方式或升级依赖后想确认没弄坏:uv run python scripts/check_wheel.py(uv build→ 干净 venv 里 wheel 与 sdist 各装一遍 → 读全 55 个快照 + 跑dh debug prompt;CI 里也会跑)。
使用
export OPENCODE_API_KEY=... # 也可放 ./.env 或 ~/.diy-harness/.env
dh # 在当前项目直接开聊(装在 PATH 里之后;`uv run dh` 同效)
uv run dh chat "你好" # 一次性提问
uv run dh chat # 交互模式:/new 重开、/exit 退出、""" 多行
uv run dh chat --show-reasoning # 显示思考过程(stderr)
uv run dh run "把 README 里过时的命令改掉" # 无交互跑一个任务(M1)
uv run dh run "跑测试并修复失败用例" --shell-allow recommended,python3,git
uv run dh run "..." --max-steps 20 # 步数用尽时退出码 3
uv run dh run "..." --rubric rubric.md # 收尾前让独立 grader 按 rubric 评(M4)
uv run dh ralph "把课程写下去" --iterations 5 # 每轮全新上下文,进度只留在文件系统与 git(M4)
uv run dh research "对比 Ralph 与 rubric 评审" # 深度研究:并行研究员 → final_report.md(M4,需要 TAVILY_API_KEY)
uv run dh mcp list # 看 .diy-harness/mcp.json 里挂了哪些 MCP 工具(M4)
uv run dh eval --split train # 跑 eval 套件:量 harness 改动值不值(M6)
uv run dh eval --split holdout --json # 只用 holdout 判改动(退出码 0 = 全过)
uv run dh say <thread> "顺手把 4 月也汇总一节" # 给跑着的会话派活(收件箱,随时可用)
uv run dh tail <thread> -f # 看它会话在干什么(像 tail -f)
uv run dh serve # 常驻会话 + 网页(手机/远程:发话、看流式、点审批;M8)
uv run dh resume <thread> # 接上继续聊;正在别处跑时会拒绝(改用 dh say)
uv run dh chat --auto-approve # 无人值守:写文件与 execute 不再询问
uv run dh debug prompt # 看拼装结果(不需要 key)
常驻会话(挂着一直聊、随时派活):dh chat 的 thread 有收件箱和单会话锁。
把 dh chat 挂在 tmux / 后台 pty 里,然后在任何终端 dh say <thread> "…" 就能派活 ——
它在下一轮开始前读收件箱(一次消费),所以不用等你在那个终端里敲键;dh tail 看进度。
同一个 thread 同一时间只允许一个进程写历史:dh resume 撞上正在跑的会话会拒绝(报持有者 PID),
dh say 不拿锁,什么时候都能投。会话历史照旧每轮落盘(~/.diy-harness/sessions/<thread>.jsonl),
收件箱与锁是同目录的 <thread>.inbox.jsonl / <thread>.lock。
在项目里直接开聊、随时换会话(像 Claude Code / Codex 那样):
cd ~/my-project
uv run dh # 直接开聊;thread 记下这是哪个目录开的
uv run dh -c # 接上本项目最近一个会话(没有就提示直接敲 dh)
uv run dh -r <ID> # 接上指定会话(ID 或前缀)
uv run dh sessions # 列会话:● = 本项目,别的地方的会带上 cwd
uv run dh sessions --here # 只看本项目的
会话里(这些命令名对齐上游 dcode;打字时敲 / 会弹出菜单,上下键选、回车执行,/resume
后面还会补会话 ID):
| 命令 | 作用 |
|---|---|
/threads(别名 /sessions) |
列会话:序号 + ID + 时间 + 条数 +(别目录的)cwd,当前那个打 *;带序号就直接切过去(/threads 2 = /resume 2) |
/resume <序号|前缀|ID> |
切过去接着问(换 thread、换历史、锁跟着搬;失败只提示不退出) |
/clear(别名 /new) |
开新 thread(锁搬到新 thread,收件箱也跟着换) |
/tokens(别名 /usage) |
这个会话用了多少 token:输入/输出/合计、缓存命中率、上下文占用、最近几轮的用量 |
/cost |
这个会话花了多少:token、缓存命中、估算花费(价格表可覆盖:~/.diy-harness/prices.json)、上下文占用百分比 |
/cwd(别名 /dir、/pwd) |
当前工作区与会话 ID |
/tools |
这次会话额外挂上的工具(MCP / 客户端 fs 等)+ 怎么看全量 |
/skills |
工作区里的 SKILL.md(渐进披露那套) |
/memory |
这次注入了哪些记忆文件(工作区 + 全局,带字符数) |
/glossary |
工作区 GLOSSARY.md 的词条 |
/init |
在工作区写一份 AGENTS.md 骨架(已存在就不动) |
/model [<ID>] |
不带参数看当前模型;带参数换一个(只影响后面的轮次) |
/mode(/mode auto) |
看/换审批档位:manual(都问,默认)/ auto(写文件放行、execute 问)/ yolo(都不问);状态栏只在非 manual 时显示 |
/compact(别名 /offload) |
把旧历史摘要掉、腾上下文(会调模型,原文备份到工作区) |
/help(别名 /h、/?) |
列这些会话命令 |
/exit(别名 /quit、/q) |
退出 |
其它子命令:dh acp 把 dh 当 ACP 服务端跑在 stdio 上(Zed 这类编辑器的
agent_servers 可以连它;协议层自己实现,见 docs/overview.md §11 M7-D)。
Zed 的接法(写进 ~/.config/zed/settings.json;本机已实测到「Zed 起得来 + 配置无报错」,
面板里选 agent 并发第一句话要你点一下——Zed 只在 Agent 面板打开时才 spawn agent server):
{
"agent_servers": {
"dh": {
"command": "dh",
"args": ["acp"],
"env": { "OPENCODE_API_KEY": "oc_sk_..." } // 或在项目 .env 里给它(dh 自己会读 .env)
}
}
}
协议能力:initialize 报 loadSession;session/new 给三档审批模式(manual / auto / yolo)并用 session/set_mode 切;
session/load 按 threadId 或「本目录最近的会话」接回历史。
客户端报了 fs 能力时,会话里会多出 client_fs_read / client_fs_write 两个工具(走编辑器自己的文件 API,未保存的缓冲区也读得到);
session/new 带的 mcpServers 会并进工作区 .diy-harness/mcp.json(同名以你已经配好的为准)。
面板里:cmd-? 打开 Agent 面板 → 顶部选 dh → 发一句话(第一次会自己跑 session/new)。
端到端自检:uv run python scripts/acp_smoke.py(起真进程 + 管道,跑一轮流式回答 + 一次审批 + 切档位 + 接历史;
需要 OPENCODE_API_KEY,缺了会跳过)。
两种 TUI:默认是行内版(下面的输入行常驻,输出往上滚);加 --fullscreen 是整屏版
(接管备用屏:可滚动的聊天面板 + 输入区 + 状态栏 + 弹窗,退出后原画面回来)。两版共用同一套
「跑一轮 / 排队 / Esc 打断 / 审批」的语义(engine.SessionEngine),只换屏幕怎么用。
行内版(默认):输入行固定在屏幕最下面,输出往上滚 —— 模型跑着的时候输入行也还在:
● edit_file(src/diy_harness/tui.py) ← 工具卡:一行一条,参数缩成相对路径
@@ -1,3 +1,4 @@
-old line
+new line ← 编辑类工具画彩色 diff(绿加红减)
⎿ Successfully replaced 1 instance(s)(共 3 行) ← 工具结果:首行 + 行数,出错标红
⠹ 正在跑 12.3s · 已排队 1 条 · esc 打断 · opencode-go · deepseek-v4.1-flash · 本会话 22.4k↑ 258↓ · 缓存 100%(16.5k/16.5k) · 上下文 7.7k
- 跑活时继续打字:回车把消息排队(状态栏显示「已排队 N 条」),这一轮完了自动发。
- Esc 打断:插旗子让 agent 循环在下一个关口停(这一轮整轮丢弃,与 Ctrl-C 一致);空闲时 Esc / Ctrl-C 清输入行,空行上 Ctrl-C 收工。状态栏跑活那段会显示耗时与转圈。
- 敲
/弹菜单:↑↓ 选、回车执行(没按过 ↑↓ 就是第一项;/+ 回车 = 先把/threads填进输入行, 再回车才跑)。/th+ 回车也能认(按唯一前缀补齐);/res 1会规范化成/resume 1。 @触发文件补全:回车把路径接进句子、留在输入行(不替你发送),写完再回车才发。- 菜单开着时状态栏第一段会提示
↑↓ 选 · Enter 执行。 - Alt+Enter / Ctrl+J 换行;↑ 翻历史(存在
~/.diy-harness/history.txt)。 - 标题加粗、代码块压灰、
`行内代码`上色;正文按行流式渲染(不做全量重排,取舍见docs/tui.md)。 - 数字是跨轮累加的,
dh -c接上老会话时会从 thread 里落盘的usage复原(不会假装从 0 开始)。 - 非 TTY(管道、脚本)会自动退回逐行模式;想手动关:
dh --plain(dh chat --plain、dh resume <ID> --plain同)。
整屏版:dh --fullscreen(dh chat --fullscreen、dh resume <ID> --fullscreen 同)。
┌ 聊天面板(可滚动,跟随最新)──────────────────────────────────────────┐
│ ● edit_file(src/diy_harness/tui.py) │
│ @@ -1,3 +1,4 @@ │
│ +new line │
│ ⎿ Successfully replaced 1 instance(s)(共 3 行) │
├ 输入区(多行;`/` 弹菜单、`@` 补文件)────────────────────────────────┤
│ dh> 把刚才那处再改回去_ │
└ 状态栏:⠹ 正在跑 12.3s · 已排队 1 条 · esc 打断 · provider · 模型 · tokens ┘
| 键 | 干什么 |
|---|---|
Enter |
提交(/ 菜单里高亮的那项先接进来,与行内版同一套语义) |
Alt+Enter / Ctrl+J |
输入区换行(多行提问) |
Esc |
关弹窗 > 打断这一轮 > 清输入行 |
Ctrl+C |
同上;输入行空着又没在跑就收工 |
PgUp / PgDn / Ctrl+U / Ctrl+D / 滚轮 |
翻聊天面板(一屏 / 半屏 / 小步) |
Ctrl+Home / Ctrl+End |
跳到最老 / 回到最新(恢复自动跟随) |
/threads、空参数的 /resume |
弹会话选择器:↑↓ 或数字选、Enter 切过去、Esc 关掉 |
审批时 y / a / n |
批准 / 这一段都不再问 / 拒绝(Esc 也=拒绝) |
管道、非 TTY 或 --plain 时照旧退回逐行模式(整屏版要真终端)。想用终端原生选择复制文字时按住 Shift 拖。
没装 tmux 也能挂(脚本只负责给 dh chat 一个 pty,派活还是走 dh say):
uv run python scripts/pty_daemon.py --log /tmp/dh-chat.log -- dh chat --auto-approve # 常驻;Ctrl-C 或 kill 收尾
uv run python scripts/pty_daemon.py --fifo /tmp/dh-chat.in -- dh chat # 想模拟键盘敲键时
printf '/exit\n' > /tmp/dh-chat.in # 从 FIFO 里敲 /exit
配了 TAVILY_API_KEY(环境变量、./.env 或 ~/.diy-harness/.env)时,工具里多一个 web_search;
fetch_url 一直都在。MCP 服务器写在 .diy-harness/mcp.json(形状同 Claude / dcode),
工具名是 mcp__<服务器>__<工具>。
MCP 工具也走审批闸门(2026-09-28 补的洞):mcp__* 工具在 manual 档一律问一句;
auto 档只放行名字看着只读的(read / list / get / search / fetch / info / tree),
写类与认不出来的照样问;yolo 档放行。MCP 是外来的能力,没法凭名字保证安全。
成本提醒:挂一个服务器就等于每次请求都带上它全部工具的说明(本机试的文件系统服务器 14 个工具 ≈ 10k token/次)。
不用的时候把 .diy-harness/mcp.json 删掉或注释掉就行(dh mcp list 随时能看挂载情况)。
默认走 OpenCode Go(https://opencode.ai/zen/go/v1)的 deepseek-v4.1-flash;
--provider opencode-go|opencode|deepseek、--model 可切换。请求头带 diy-harness/<版本>
与每个会话固定的 x-opencode-session。
自演进(dh evolve)
dh evolve 是个无人值守循环:plan → work → check → record,一轮改一个增量。工作区里要有
MISSION.md(只读,启动时记 SHA-256,被改过就停)与 STATUS.md(状态思考 + 每轮记录),
全过程另存 .diy-harness/evolve/(journal.md append-only 日志、每阶段完整输出、A/B 快照、候选快照)。
# 在一个新目录里跑(工作区里先放 MISSION.md)
dh evolve --rounds 3 --max-steps 25 --max-tokens 400000
# harness 自改(M5-D):把自己当工作区,判分器是 dh eval
dh evolve --repo . --ab --candidates 2 \
--allow-paths src/diy_harness,prompts,docs,tests,TASKS.md,README.md \
--plan-max-steps 10 --max-steps 30
三个让「自改」可控的开关(都能在命令行上调,按自己的想法配):
| 开关 | 作用 |
|---|---|
--ab |
work 前后各跑一遍任务书里的验收命令,把「这轮是变好还是变差」写进记录(- A/B:通过 0/2 → 2/2;退步 0 条),check 阶段也看得到这份对照 |
--candidates N |
一轮最多试 N 条候选:每条 work→check,评审不过就回滚(文件快照,不依赖 git)再试下一条;失败的也记账 |
--allow-paths |
work/check 只许写这些前缀(相对工作区)。越界当场被拒、记账、本轮退出码 7;MISSION.md / STATUS.md / .diy-harness/ 永远不许写 |
退出码:0 正常 / 3 步数用尽 / 4 预算到点 / 5 评审连续 FAIL / 6 任务书被改 / 7 越界写入。
操作闸门:.diy-harness/STOP 存在即停;.diy-harness/STEER.md 写一句话给下一轮当指令(读一次后清空)。
定时自己干活(dh schedule)
清单写在工作区 .diy-harness/schedule.toml:
[[job]]
thread = "20260928-073801-06d72d" # 会话 ID(可只给前缀)
when = "every 6h" # in 30m / every 6h / at 2026-09-30 08:00 / daily at 08:00
prompt = "检查 CI,挂了就修"
dh schedule list # 列出来(含上次跑过的时间)
dh schedule run # 把到点的活投进那个会话的收件箱(跑一次就退出,丢给 cron/launchd 即可)
到点的活走的是 dh say 同一条路(收件箱),所以「会话在跑就先排队、不在跑就留着等下轮」这套语义直接复用;
in / at 是一次性的(投完标 done),every / daily 记 last_run。我们不做常驻守护进程 ——
触发交给系统 cron / launchd,这也顺应上游 libs/talon 的结论(见 docs/upstream-audit.md §四.3)。
手机 / 远程(dh serve)——第三个 UI
dh serve 把常驻会话开成一个网页(HTTP + SSE):手机浏览器打开就能发话、看流式输出、点审批。
干活仍然全部走 engine.SessionEngine —— 排队 / 打断 / 审批与两个 TUI 是同一份实现,
所以 dh say / dh tail / dh resume 在这边照样能用(同一个 thread、同一把锁)。
dh serve # 本项目最近的会话(没有就新开);打印带 token 的地址
dh serve --mode auto # 写文件放行、execute 仍问(问了就在页面上点)
dh serve --port 8787 --token … # 端口与令牌(省略则读/建 ~/.diy-harness/serve-token,0600)
页面上的动作对应四条 POST:say(≡ dh say,走收件箱)、approve(y = 允许一次 / a = 这一段都允许 /
n = 拒绝)、interrupt(等价在终端按 Esc)、shutdown(常驻进程收工)。审批卡片带 diff;
没人回(默认 300 秒)按拒绝处理。SSE 带最近 200 条回放,手机断线重连不用从头再聊。
安全:默认只绑 127.0.0.1;要手机访问优先 tailscale serve --bg 8787(自动 HTTPS、只在 tailnet 内可见),
执意直连再加 --allow-remote。所有路由都要 token(页面与 SSE 走 ?token=,其余走 Authorization: Bearer)。
不想开网页? 还有零代码那条路:手机 SSH 进 Mac,dh say 派活 / dh tail 看进度 / 往键盘 FIFO
printf 'y\n' 答审批 —— 起法、四个坑与彩排记录见 docs/mobile.md(scripts/resident.sh)。
沙箱与安全边界(M9)
现状:M9-A(补洞)已落地;容器后端(M9-B)与网络白名单(M9-C)未做 —— 细节与局限见
docs/sandbox.md。不带 Docker 也已经生效的三件事:
- 子进程环境是白名单:
execute与 MCP 服务器只继承PATH/HOME/LANG/LC_*… 这类基础变量;*_API_KEY之外的密钥名(GITHUB_TOKEN、AWS_SECRET_ACCESS_KEY)一并不给。 配置里显式写的env(含${VAR}展开)照给 —— 那是用户自己的选择。 - 密钥文件对工具与命令不可见:
~/.diy-harness/.env、serve-token、trusted.json、工作区根的.env*——read_file/grep/glob都碰不到,cat ~/.diy-harness/.env这类命令会被拦下;.env.example这类模板照旧可见。记忆 / 词表 / skills 所在的~/.diy-harness/agent/不受影响。 - 工作区配置要信任:
.diy-harness/hooks.toml与mcp.json是会执行命令的配置。交互模式第一次会问 一句[y/N];非交互入口(run/ralph/serve/acp/evolve/mcp list)默认不加载并打一行说明:
dh run "…" --trust-config # 显式信任(记进 ~/.diy-harness/trusted.json,之后不再问)
rm ~/.diy-harness/trusted.json # 全部撤销(内容一改其实就自动失效)
没有沙箱却用 --mode yolo 或 --shell-allow all 时,启动会打一行红字、TUI 状态栏也把它排在最前面 ——
那等于把宿主机交给模型,只适合在一次性目录里跑(容器支持是 M9-B)。
容器后端(M9-B):--sandbox docker 让 execute / MCP / hooks / evolve 验收命令进容器
(无网络、只有工作区可写、没有 key、有资源上限),文件工具与 API key 留在宿主机:
dh sandbox build # 一次性:构建镜像(docker/sandbox/Dockerfile + 代理镜像)
dh chat --sandbox docker # 交互模式进容器
dh run "把测试修到全绿" --sandbox docker
dh chat --sandbox docker --sandbox-net allowlist # 网络只走代理、只放名单里的域名(M9-C)
dh mcp list --sandbox docker # MCP 服务器也进容器(M9-D);需要网络的服务器在 mcp.json 里写 sandboxDomains
DIY_HARNESS_SANDBOX=docker dh # 环境变量版
dh sandbox gc # 清掉属主进程已死的残留容器/网络
细节(四条边界、四类攻击的红队、局限)见 docs/sandbox.md。
钩子(hooks.toml)——「每次都要做的事」交给 harness
工作区里写 .diy-harness/hooks.toml,三条钩子都是命令模板(不用写 Python):
[hooks]
session_start = "echo 开工:{workspace}"
before_tool = "python3 tools/policy.py {tool} {path}" # 非 0 退出 = 拦下这一步
sort_check = "" # ← 不认识的键会直接报错,不会静默忽略
after_tool = "ruff format {path} 2>/dev/null || true" # 只在 write_file / edit_file 成功之后跑
占位符:{tool}、{path}、{command}(execute 的命令)、{workspace};before_tool 想拦就 exit 1
(模型会收到「被 before_tool 拦下」并看到你的输出),after_tool 失败只提示、不回滚。没有这个文件就是全关(默认什么都不做)。
发布(PyPI,M10)
包名 diy-harness(命令仍是 dh;PyPI 上 diy-harness 与 diy_harness 是同一个项目)。
版本号只有一处:pyproject.toml 的 version —— 另外只多一个 diy_harness.__version__
(dh --version 读它),两处漂移有契约测试钉着(tests/unit_tests/test_packaging.py)。
uv version --bump minor # 0.1.0 → 0.2.0;再手动改 src/diy_harness/__init__.py
uv run pytest tests/unit_tests/test_packaging.py -q # 漏改一处在这里就挂
git commit -am "M10:版本 0.2.0"
git tag v0.2.0 && git push origin main v0.2.0 # 推 tag = 发布(见下)
- 推
v*tag 就是发布:.github/workflows/publish.yml先查 tag 与pyproject的版本一致(不一致直接拒 —— 版本号在 PyPI 上用掉就回不来)、跑测试与产物验收、uv build+uvx twine check,然后经 trusted publishing(GitHub OIDC)上传:仓库里不存任何 PyPI token。workflow_dispatch只做「构建 + 校验」那一半,想先看产物过不过就手动跑一次。 - PyPI 侧只配一次:https://pypi.org/manage/account/publishing/ 建 pending publisher ——
Owner
zxu756、Repositorydiy-harness、Workflowpublish.yml、Environmentpypi(最后一项要和 workflow 里的environment:一字不差)。 - 手动发(本机,要 token):
uv build && uv publish(token 走UV_PUBLISH_TOKEN或--token)。 想先拿 TestPyPI 试水:配一个[[tool.uv.index]](publish-url指 TestPyPI),再uv publish --index testpypi。 - 发布前自检四条:
uv run pytest、uv run ruff check .、uv run python scripts/check_wheel.py、uvx twine check dist/*。README 就是 PyPI 上的长描述,正文里的链接一律写绝对地址(相对链接在 PyPI 上点不开)。 - 版本策略:0.x 期间功能里程碑
+minor、修 bug+patch;上传成功的版本号不能改也不能删,只能 yank。
目录
evals/ 评测套件:25 个固定任务(train 15 / holdout 10)+ 判分脚本 + 成绩单(M6/M6-I)
prompts/upstream/ 上游提示词快照 55 个(脚本生成,不手改;来源见 UPSTREAM.md)
prompts/dcode/ 派生的 dcode 主提示词(无交互变体;删改登记在 DEVIATIONS.md)
prompts/DEVIATIONS.md 派生提示词的改动记录
scripts/sync_prompts.py 从固定 commit 抽取快照(--check 只比对)
scripts/pty_daemon.py 给常驻会话一个 pty 的最小载体(没 tmux 时用;不属于运行时)
src/diy_harness/ 运行时(agent / tools / llm / prompts / prompting / chat / terminal / cli / config)
tests/unit_tests/ 单元测试
tests/integration_tests/ 真实 API 调用(需要 key,用 -m integration 跑)
Metadata
Release files for diy-harness 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| diy_harness-0.1.0.tar.gz | 291.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| diy_harness-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 625.4 kB
Release files / diy_harness-0.1.0.tar.gz
| Download URL | diy_harness-0.1.0.tar.gz |
|---|---|
| Size | 291.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a4f96264cf601176278dab6bb1f5f59af1b6cdc513fe31ca3cedc820b08da3ef
|
|
BLAKE2b-256 checksum How to use checksums |
3be2a049bbc9dd3309b18e1228d265620967ee79807f689f05ee43d466ad285b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.
Transparency logRelease files / diy_harness-0.1.0-py3-none-any.whl
| Download URL | diy_harness-0.1.0-py3-none-any.whl |
|---|---|
| Size | 333.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9bb410cfb877ebba32125c2e4c64ccbc54f6121c355a519bdc052e26f7093907
|
|
BLAKE2b-256 checksum How to use checksums |
e91654d53e6dff499d7d22720ab73e6cf41862009a994ad444632d15267b2d4c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.
Transparency log