
Claim Ledger
- 24 installs
- 1 repo stars
- Updated July 31, 2026
- hexbee/hello-skills
Turns research and writing claims into a verifiable Claim-Evidence-Boundary ledger, forcing evidence, counter-examples, and publishability judgments.
About
A research-rigor skill that breaks each claim into claim, evidence, and boundary with nine required fields per row. A writer or researcher uses it to make conclusions traceable and refutable before publishing a thread or long-form piece.
- Nine mandatory fields per claim including confidence, source grade, and counter-evidence
- Publishability verdict: publishable / needs rewrite / not publishable
Claim Ledger by the numbers
- 24 all-time installs (skills.sh)
- Ranked #973 of 1,879 Documentation skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/hexbee/hello-skills --skill claim-ledgerAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 24 |
|---|---|
| repo stars | ★ 1 |
| Last updated | July 31, 2026 |
| Repository | hexbee/hello-skills ↗ |
What it does
Turns research and writing claims into a verifiable Claim-Evidence-Boundary ledger, forcing evidence, counter-examples, and publishability judgments.
Files
Claim Ledger
何时使用
当用户出现以下意图时使用本技能:
- “先做研究框架/证据链,再写内容”
- “判断某观点是否可发、是否站得住”
- “把资料堆整理成可发布结论”
- “让 AI 先出 Ledger 再出线程/长文”
核心定义
Claim Ledger 把每条观点拆成三部分:
Claim:要让读者相信的主张Evidence:支持该主张的证据Boundary:成立条件与失效条件
目标:让每个结论都可追溯、可反驳、可复核。
最小字段(必填 9 项)
每条 Claim 一行,必须包含:
1. Claim ID:C01/C02/... 2. Claim:一句可检验陈述 3. Type:事实/解释/预测/建议 4. Confidence:高/中/低 5. Evidence:E01,E02...(至少 2 条) 6. Source Grade:S/A/B/⚠️ 7. Counter:至少 1 条反证/反例;无则写“未找到,风险=高” 8. Boundary:成立条件 + 失效条件 9. Publishability:可发/需改写/不可发
Evidence Card 规范
每条证据必须是可复核卡片,而非泛化描述。字段:
Source:标题 + 作者/机构 + 日期Link:URL 或文档定位Quote/Data:关键原话或数字Supports:支持 Claim 的哪一部分Reliability:S/A/B/⚠️+ 评级理由Freshness:是/否(是否过时)
经验规则:
- 事实型 Claim:至少 1 条
S或A - 解释型 Claim:至少 2 条跨来源交叉
- 预测/建议型 Claim:必须有历史对比或失败条件,否则降为低置信度
六步流程(从资料堆到可发布)
1. 先写 5 条候选 Claim(先定义要证明什么) 2. 给每条 Claim 标注类型(事实/解释/预测/建议) 3. 每条补 2-4 条证据(优先一手源) 4. 强制补反证/反例(没有也要显式记录) 5. 写边界(成立条件与失效条件) 6. 打置信度和可发布性(必要时降调措辞)
质量闸门(必须执行)
以下任一不满足,则禁止进入内容生成:
- 任一 Claim 证据少于 2 条
- 任一 Claim 缺少 Counter
- 任一 Claim 缺少 Boundary
预测/建议Claim 无失败条件
处理规则:
- 证据不足:降级为“猜测(低置信度)”
- 语气要求:不得使用确定性措辞
与内容生产的映射
线程映射(推荐)
3 个 Claim × 4 条推 = 12 条线程- 每组 4 条顺序:
1. Claim 2. Evidence 3. Boundary 4. Action
长文映射(推荐)
每个 Claim 作为一节:
- 结论 -> 证据 -> 反方风险 -> 边界 -> 小结/清单
默认输出格式
1. Claim Ledger 表(至少 3 条 Claim) 2. Evidence Cards(与 Ledger 的 E# 对齐) 3. Gate Check(逐条列出通过/失败项) 4. 若 Gate 全通过,才生成目标内容(线程/长文/脚本)
执行指令模板
先输出 Claim Ledger(至少 3 条 Claim,每条 >=2 条证据 + >=1 条反证 + 边界)。
未满足质量闸门前,不允许生成正文。
若证据不足,必须降级为“猜测(低置信度)”,并避免确定性语气。参考模板与示例
需要直接套用表格和卡片时,读取:
references/templates.md
需要自动校验 Ledger 质量闸门时,运行:
scripts/validate_ledger.py --file <ledger.md>
interface:
display_name: "Claim Ledger"
short_description: "Force claim-evidence-boundary checks before content generation"
default_prompt: "Build a Claim Ledger first (>=3 claims, >=2 evidence each, counterexample and boundary required), then generate publishable content only after gate checks pass."
interface:
display_name: "Claim Ledger"
short_description: "Validate claims with evidence and boundaries"
default_prompt: "Build a Claim Ledger first: define claims, supporting evidence, counterexamples, and validity boundaries before generating publishable content."
Claim Ledger Templates
Ledger 表(最小版)
| ID | Claim | Type | Conf | Evidence (E#) | Source Grade | Counter | Boundary | Publish |
|-----|-------|------|------|---------------|--------------|---------|----------|---------|
| C01 | ... | ... | ... | E01,E02 | A,B | ... | ... | ... |
| C02 | ... | ... | ... | E03,E04 | S,A | ... | ... | ... |
| C03 | ... | ... | ... | E05,E06 | A,B | ... | ... | ... |Evidence Card(每条 E# 一段)
E01
- Source: 标题 + 作者/机构 + 日期
- Link: URL 或文档定位
- Quote/Data: 可复核原话或数字
- Supports: 支持 C0X 的哪一段
- Reliability: S/A/B/⚠️,以及评级理由
- Freshness: 是/否(是否过时)Gate Check(正文前检查)
Gate Check
- [ ] 每条 Claim >= 2 条证据
- [ ] 每条 Claim >= 1 条反证/反例
- [ ] 每条 Claim 有成立条件与失效条件
- [ ] 预测/建议型 Claim 有失败条件
- [ ] 证据不足的 Claim 已降级为低置信度并降调语气线程映射模板(12 条)
Claim 1:
1) Claim
2) Evidence
3) Boundary
4) Action
Claim 2:
5) Claim
6) Evidence
7) Boundary
8) Action
Claim 3:
9) Claim
10) Evidence
11) Boundary
12) Action#!/usr/bin/env python3
"""Validate Claim Ledger markdown without external dependencies."""
import argparse
import io
import json
import os
import re
import sys
REQUIRED_FIELDS = [
"id",
"claim",
"type",
"confidence",
"evidence",
"sourcegrade",
"counter",
"boundary",
"publishability",
]
def normalize_header(value):
text = value.strip().lower()
text = text.replace("claim id", "id")
text = text.replace("claim_id", "id")
text = text.replace("conf", "confidence")
text = text.replace("publish", "publishability")
text = re.sub(r"\(.*?\)", "", text)
text = re.sub(r"[^a-z0-9\u4e00-\u9fff]+", "", text)
mapping = {
"id": "id",
"编号": "id",
"主张id": "id",
"claim": "claim",
"主张": "claim",
"type": "type",
"类型": "type",
"confidence": "confidence",
"置信度": "confidence",
"evidence": "evidence",
"证据": "evidence",
"证据条目": "evidence",
"sourcegrade": "sourcegrade",
"来源等级": "sourcegrade",
"counter": "counter",
"反证": "counter",
"反例": "counter",
"boundary": "boundary",
"边界": "boundary",
"适用边界": "boundary",
"publishability": "publishability",
"可发布性": "publishability",
}
return mapping.get(text, text)
def parse_markdown_table(lines):
i = 0
while i < len(lines):
line = lines[i].strip()
if "|" not in line:
i += 1
continue
if i + 1 >= len(lines):
i += 1
continue
separator = lines[i + 1].strip()
if "|" not in separator or "-" not in separator:
i += 1
continue
headers = [x.strip() for x in line.strip("|").split("|")]
normalized = [normalize_header(x) for x in headers]
if "id" not in normalized or "claim" not in normalized:
i += 1
continue
rows = []
j = i + 2
while j < len(lines):
row = lines[j].strip()
if not row.startswith("|") or "|" not in row:
break
cells = [x.strip() for x in row.strip("|").split("|")]
if len(cells) < len(headers):
cells.extend([""] * (len(headers) - len(cells)))
row_obj = {}
k = 0
while k < len(headers):
row_obj[normalized[k]] = cells[k] if k < len(cells) else ""
k += 1
rows.append(row_obj)
j += 1
if rows:
return normalized, rows
i += 1
return [], []
def parse_evidence_cards(text):
cards = {}
lines = text.splitlines()
current = None
buffer_lines = []
def flush():
if current is not None:
cards[current] = "\n".join(buffer_lines).strip()
for raw in lines:
line = raw.strip()
m = re.match(r"^(E\d{2,3})\s*:?\s*$", line, re.IGNORECASE)
if m:
flush()
current = m.group(1).upper()
buffer_lines = []
continue
if current is not None:
buffer_lines.append(raw.rstrip())
flush()
return cards
def extract_evidence_ids(value):
found = re.findall(r"\bE\d{2,3}\b", value.upper())
ordered = []
seen = set()
for item in found:
if item not in seen:
ordered.append(item)
seen.add(item)
return ordered
def has_failure_condition(boundary):
text = boundary.strip().lower()
if not text:
return False
failure_tokens = [
"失效",
"不成立",
"失败",
"不适用",
"除非",
"otherwise",
"unless",
"fails",
"not valid",
]
for token in failure_tokens:
if token in text:
return True
return False
def has_success_condition(boundary):
text = boundary.strip().lower()
if not text:
return False
success_tokens = ["成立", "适用", "条件", "when", "if", "under"]
for token in success_tokens:
if token in text:
return True
return False
def is_predictive_or_advice(type_value):
text = type_value.strip().lower()
return (
"预测" in text
or "建议" in text
or "prediction" in text
or "forecast" in text
or "recommendation" in text
or "advice" in text
)
def validate_rows(headers, rows, evidence_cards, strict_mode):
results = []
global_issues = []
missing_headers = [h for h in REQUIRED_FIELDS if h not in headers]
if missing_headers:
global_issues.append(
"Missing required columns: " + ", ".join(missing_headers)
)
if len(rows) < 3:
global_issues.append("Claim count is less than 3.")
for row in rows:
claim_id = row.get("id", "").strip() or "UNKNOWN"
issues = []
warnings = []
evidence_ids = extract_evidence_ids(row.get("evidence", ""))
if len(evidence_ids) < 2:
issues.append("Evidence count < 2.")
counter = row.get("counter", "").strip()
if not counter:
issues.append("Counter is required.")
boundary = row.get("boundary", "").strip()
if not boundary:
issues.append("Boundary is required.")
else:
if not has_success_condition(boundary):
warnings.append("Boundary may be missing success condition.")
if not has_failure_condition(boundary):
issues.append("Boundary is missing failure condition.")
if is_predictive_or_advice(row.get("type", "")) and not has_failure_condition(boundary):
issues.append("Predictive/advice claim must include failure condition.")
if strict_mode:
missing_cards = []
for e_id in evidence_ids:
if e_id not in evidence_cards:
missing_cards.append(e_id)
if missing_cards:
issues.append(
"Missing evidence cards: " + ", ".join(missing_cards)
)
results.append(
{
"claim_id": claim_id,
"valid": len(issues) == 0,
"issues": issues,
"warnings": warnings,
"evidence_ids": evidence_ids,
}
)
return global_issues, results
def load_text(path):
if not os.path.exists(path):
print("File not found: {0}".format(path), file=sys.stderr)
sys.exit(2)
with io.open(path, "r", encoding="utf-8") as f:
return f.read()
def parse_args():
parser = argparse.ArgumentParser(
description="Validate Claim Ledger markdown files."
)
parser.add_argument("--file", required=True, help="Path to markdown ledger file.")
parser.add_argument(
"--strict",
action="store_true",
help="Require all referenced E## evidence cards to exist in file.",
)
parser.add_argument("--json", action="store_true", help="Output JSON.")
return parser.parse_args()
def main():
args = parse_args()
text = load_text(args.file)
lines = text.splitlines()
headers, rows = parse_markdown_table(lines)
evidence_cards = parse_evidence_cards(text)
global_issues, results = validate_rows(headers, rows, evidence_cards, args.strict)
all_valid = len(global_issues) == 0 and all(item["valid"] for item in results)
payload = {
"file": args.file,
"valid": all_valid,
"global_issues": global_issues,
"claims": results,
"evidence_card_count": len(evidence_cards),
}
if args.json:
print(json.dumps(payload, ensure_ascii=True, indent=2))
return
print("Claim Ledger Validation: {0}".format("PASS" if all_valid else "FAIL"))
print("File: {0}".format(args.file))
if global_issues:
print("Global issues:")
for issue in global_issues:
print(" - {0}".format(issue))
for item in results:
status = "PASS" if item["valid"] else "FAIL"
print("[{0}] {1}".format(status, item["claim_id"]))
if item["evidence_ids"]:
print(" Evidence: {0}".format(", ".join(item["evidence_ids"])))
if item["warnings"]:
for warning in item["warnings"]:
print(" WARN: {0}".format(warning))
if item["issues"]:
for issue in item["issues"]:
print(" - {0}".format(issue))
sys.exit(0 if all_valid else 1)
if __name__ == "__main__":
main()