diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml new file mode 100644 index 0000000..1616c1c --- /dev/null +++ b/.github/workflows/check.yml @@ -0,0 +1,16 @@ +name: check + +on: + push: + pull_request: + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.13" + - name: Front matter, relative links, README counts, example compiles + run: python3 tests/check_kit.py diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f83fef2..63ae0b8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,3 +11,11 @@ These agents come from running real deals. If you've improved one, or built a ne 4. Open a PR describing the deal situation it's for and what it returns. **Not legal/financial advice.** Agents here are analytical tools, not investment, legal, tax or accounting advice. Contributions should preserve that framing. + +**Checks.** `python3 tests/check_kit.py` runs on every push: each agent and system has `name` and `description` +front matter, every relative link resolves, the README's counts (20 agents, 4 systems, 100+ prompts, 50+ skills) +still hold, and the one Python example compiles. Run it before opening a PR; it needs nothing installed. + +**Reporting a wrong output.** Open an issue with the agent or system you used, the prompt exactly as you pasted it, +the passage of the document it read (redacted as you need), the output, and the claim that had no page behind it +or cited the wrong one. A fabricated figure that slipped through is the report that matters most. diff --git a/README.md b/README.md index a77dff5..761a40f 100644 --- a/README.md +++ b/README.md @@ -33,10 +33,16 @@ The flagship is the **[Cited Brief System](systems/cited-brief-system/SKILL.md)* ```bash git clone https://github.com/MariusGithub13/open-deal-kit.git -cp -r open-deal-kit/agents/* ~/.claude/skills/ -cp -r open-deal-kit/systems/* ~/.claude/skills/ +mkdir -p ~/.claude/skills +cp -r open-deal-kit/agents/*/ ~/.claude/skills/ +cp -r open-deal-kit/systems/*/ ~/.claude/skills/ ``` +The `mkdir` matters on a machine that has never had a skill installed; without it `cp` stops with "No such file or +directory". The trailing `*/` copies the 24 skill folders and leaves the two index READMEs behind. Every skill file's +front matter and every relative link in the kit is checked on each push by `tests/check_kit.py`; what was run and +checked on 15 October 2026, including every external link, is in [docs/README-PROOF-2026-10-15.md](docs/README-PROOF-2026-10-15.md). + ### The one habit that makes this work When a tool gives you a number that matters, **check the citation it points to.** Every figure should trace back to a line in your document. If it can't, treat it as unverified. That single habit is the difference between *using* AI on a deal and *trusting* it. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..0c9150a --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,9 @@ +# Security + +The kit is prompts and skill files; nothing here runs on its own or sends anything anywhere. Two things do +act: the example in `examples/typed-refusal-gate/` downloads four public PDFs from `os.devaland.com` and +installs a third-party package from a pinned commit, and anything you paste into a prompt goes wherever that +chat goes, so keep deal documents out of the issues here. + +To report a security problem, write to office@devaland.com with the file, the commit and a way to reproduce +it. Please do not open a public issue for it. A person answers; there is no bug bounty. diff --git a/docs/README-PROOF-2026-10-15.md b/docs/README-PROOF-2026-10-15.md new file mode 100644 index 0000000..f89ded1 --- /dev/null +++ b/docs/README-PROOF-2026-10-15.md @@ -0,0 +1,111 @@ +# README proof, 15 October 2026 + +Everything the README asks a reader to run, run on a clean clone of `main` (commit `e6fefa3`) in a cloud +container: Ubuntu 24.04, Python 3.13.16, outbound network limited to a short allow-list. The kit is prose, so +most of what can be checked is that the files, counts, front matter and links are what the README says they are. + +Legend: **passed** means it ran and matched. **not run here** means the container lacks something it needs, +with the reason. **not verified here** means a link the container was not allowed to reach. Nothing below is +inferred; every output line was produced in this session. + +## The install commands + +```bash +git clone https://github.com/MariusGithub13/open-deal-kit.git +cp -r open-deal-kit/agents/* ~/.claude/skills/ +cp -r open-deal-kit/systems/* ~/.claude/skills/ +``` + +**Failed as written on a fresh home directory**, passed with one extra line: + +``` +$ cp -r open-deal-kit/agents/* ~/.claude/skills/ (HOME with no .claude/skills yet) +cp: target '/tmp/tmp.W0sVIRLh04/.claude/skills/': No such file or directory +[exit 1] +$ mkdir -p ~/.claude/skills && cp -r open-deal-kit/agents/* ~/.claude/skills/ && cp -r open-deal-kit/systems/* ~/.claude/skills/ +25 entries: the 24 skill folders plus one README.md (systems/README.md written over agents/README.md) +$ mkdir -p ~/.claude/skills && cp -r open-deal-kit/agents/*/ ~/.claude/skills/ && cp -r open-deal-kit/systems/*/ ~/.claude/skills/ +24 entries, 0 README.md, each folder holds its SKILL.md +``` + +README corrected: `mkdir -p ~/.claude/skills` added, `*` became `*/`. + +## The counts on the first line of the README + +| README says | Counted | How | +|---|---|---| +| 100+ prompts | 103 | numbered items in `prompts/README.md` (8 + 20 + 19 + 10 + 10 + 13 + 11 + 12) | +| 50+ skills | 52 | table rows in `skills/README.md` (12 + 12 + 10 + 10 + 8) | +| 20 agents | 20 | `agents/*/SKILL.md` | +| 4 systems | 4 | `systems/*/SKILL.md` | + +All 24 `SKILL.md` files open with front matter carrying `name` and `description`. 65 relative links across +every Markdown file resolve. `grep` finds no em dash in the README or any skill file, as the 21 June +changelog entry says. These checks are now `tests/check_kit.py`, run by the workflow on every push: + +``` +$ python3 tests/check_kit.py +20 agents, 4 systems, 103 prompts, 52 skills, 65 relative links checked +OK +[exit 0] +``` + +## Every external link, in the README and in the agents' files + +Fetched with `curl -L` from the container and, where that was refused, through the session's web fetch tool. + +| URL | In | Result | +|---|---|---| +| https://github.com/MariusGithub13/open-deal-kit.git | README | **200**, the repository page | +| https://claude.com/claude-code | README | **200**, the product page | +| https://claude.ai | README | **403** to a non-browser client, with the bot-check page ("Just a moment..."); a browser gets the site. Not dead | +| https://devaland.com | README (3 times) | **not verified here**: the egress proxy refuses the host (`CONNECT tunnel failed, response 403`), and the web fetch tool cannot resolve it | +| https://os.devaland.com/sample-brief | README, the four index READMEs, all 20 agent files, all 4 system files | **not verified here**, same reason. This is the repository's homepage and the kit's one demonstration link, so it is the first thing to check from a normal network | +| https://os.devaland.com/static/sample-sources/ and the four `Sentinel_*.pdf` files | `examples/typed-refusal-gate/` | **not verified here**, same reason | +| https://github.com/GrayWolfOne21/typed-refusal | `examples/typed-refusal-gate/` | **exists** (web fetch tool): description "Fail-closed typed refusal contract...", MIT, 4 commits, no release named v0.1.1. `curl` from the container got 403 from the proxy | + +Dead links found: **none**. Links not verifiable from this session: the Devaland ones above. No link was +changed. + +## `examples/typed-refusal-gate/` + +``` +$ pip install "git+https://github.com/GrayWolfOne21/typed-refusal@892b0a0" +Successfully installed typed-refusal-0.1.0 +[exit 0] +$ python3 -c "from typed_refusal import Contract, FieldRule, evaluate; from typed_refusal.contract import Source; from typed_refusal.gate import seal" +imports ok +$ python3 gate_sentinel.py +urllib.error.URLError: +[exit 1] +``` + +The install **passed** (pip reaches GitHub through the git proxy). The package at the pinned commit reports +version 0.1.0 while the example calls it v0.1.1; the typed-refusal repository has no releases, so "v0.1.1" is the +label the two authors use for that commit. Left as written, noted here. The script itself is **not run here**: +its first step downloads the four PDFs from `os.devaland.com`, which the container cannot reach. The committed +`receipt.json` reads `status DATA_NULL`, `brief_written false`, two `not_ready` and three `data_null` fields, and +all five seal checks `true`, which is what the example README's table says. + +## Claims checked by reading + +| Claim | Result | +|---|---| +| Each agent is "an installable skill with a copy-ready prompt" | 20 of 20 have front matter and a prompt section | +| The flagship pair, Cited Brief System and Citation Checker, exists at the paths given | both files present | +| MIT licence | `LICENSE` | +| The changelog's version history for the Cited Brief System | dates and version numbers consistent between `CHANGELOG.md` and the skill file | +| "Twenty Claude agents", the GitHub description | 20 folders | + +Not checkable here: anything about what the prompts produce when run against a deal. Nothing of that kind was +added to the README. + +## What changed in the README, and why + +1. `mkdir -p ~/.claude/skills` before the two `cp` lines: without it the install fails on a fresh machine. +2. `agents/*` and `systems/*` became `agents/*/` and `systems/*/`: the bare glob also copies the two index + READMEs into the skills directory, one over the other. +3. One paragraph saying what the check script verifies and pointing to this document. + +Nothing else was changed. `CONTRIBUTING.md` gained two paragraphs (how to run the check, how to report a wrong +output with the input that produced it); the author's text above them is untouched. `SECURITY.md` is new. diff --git a/tests/check_kit.py b/tests/check_kit.py new file mode 100644 index 0000000..20f7818 --- /dev/null +++ b/tests/check_kit.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +"""The kit is prose, so this checks what prose can be checked: every agent and system is a skill file with +`name` and `description` front matter, every relative link resolves, the README's counts hold, and the one +Python example compiles. It asks no model and needs nothing installed.""" +import glob, os, py_compile, re, sys + +ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +os.chdir(ROOT) +errors = [] + + +def frontmatter(path): + text = open(path, encoding="utf-8").read() + if not text.startswith("---\n"): + return {} + head = text[4:].split("\n---", 1)[0] + return dict(line.split(":", 1) for line in head.splitlines() if ":" in line) + + +agents = sorted(glob.glob("agents/*/SKILL.md")) +systems = sorted(glob.glob("systems/*/SKILL.md")) +for f in agents + systems: + fm = frontmatter(f) + for key in ("name", "description"): + if not fm.get(key, "").strip(): + errors.append(f"{f}: front matter has no {key}") +if len(agents) != 20: + errors.append(f"README says 20 agents, found {len(agents)}") +if len(systems) != 4: + errors.append(f"README says 4 systems, found {len(systems)}") + +prompts = len(re.findall(r"^\d+\. ", open("prompts/README.md", encoding="utf-8").read(), re.M)) +if prompts < 100: + errors.append(f"README says 100+ prompts, prompts/README.md numbers {prompts}") +rows = re.findall(r"^\| ([^|]+) \| [^|]+ \|$", open("skills/README.md", encoding="utf-8").read(), re.M) +skills = [r for r in rows if r.strip() not in ("Skill",) and not r.startswith("-")] +if len(skills) < 50: + errors.append(f"README says 50+ skills, skills/README.md lists {len(skills)}") + +links = 0 +for f in glob.glob("**/*.md", recursive=True): + for m in re.finditer(r"\]\(([^)]+)\)", open(f, encoding="utf-8").read()): + target = m.group(1).split()[0].split("#")[0] + if not target or target.startswith(("http://", "https://", "mailto:")): + continue + links += 1 + if not os.path.exists(os.path.normpath(os.path.join(os.path.dirname(f), target))): + errors.append(f"{f}: dead relative link {m.group(1)}") + +try: + py_compile.compile("examples/typed-refusal-gate/gate_sentinel.py", doraise=True) +except py_compile.PyCompileError as e: + errors.append(str(e)) + +print(f"{len(agents)} agents, {len(systems)} systems, {prompts} prompts, {len(skills)} skills, {links} relative links checked") +for e in errors: + print("FAIL", e) +print("OK" if not errors else f"{len(errors)} problem(s)") +sys.exit(1 if errors else 0)