hermeneutic 0.1.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hermeneutic-0.1.7/.gitignore +16 -0
- hermeneutic-0.1.7/.zenodo.json +24 -0
- hermeneutic-0.1.7/AGENTS.md +84 -0
- hermeneutic-0.1.7/BACKLOG.md +11 -0
- hermeneutic-0.1.7/CHANGELOG.md +74 -0
- hermeneutic-0.1.7/CITATION.cff +39 -0
- hermeneutic-0.1.7/CLAUDE.md +27 -0
- hermeneutic-0.1.7/CODE_OF_CONDUCT.md +5 -0
- hermeneutic-0.1.7/CONTRIBUTING.md +86 -0
- hermeneutic-0.1.7/FORWARD-DEPLOYED-HARNESS.md +219 -0
- hermeneutic-0.1.7/INTENT.md +34 -0
- hermeneutic-0.1.7/LICENSE +21 -0
- hermeneutic-0.1.7/PKG-INFO +430 -0
- hermeneutic-0.1.7/README.md +395 -0
- hermeneutic-0.1.7/SECURITY.md +81 -0
- hermeneutic-0.1.7/claude-plugin/.claude-plugin/plugin.json +11 -0
- hermeneutic-0.1.7/claude-plugin/hooks/hooks.json +11 -0
- hermeneutic-0.1.7/claude-plugin/scripts/hermeneutic-gate.py +92 -0
- hermeneutic-0.1.7/codex-plugin/.codex-plugin/plugin.json +17 -0
- hermeneutic-0.1.7/codex-plugin/hooks/hooks.json +11 -0
- hermeneutic-0.1.7/codex-plugin/scripts/codex-gate.py +66 -0
- hermeneutic-0.1.7/demo.tape +26 -0
- hermeneutic-0.1.7/docs/THEORY.md +75 -0
- hermeneutic-0.1.7/docs/demo.gif +0 -0
- hermeneutic-0.1.7/evals/bucket-discrimination/RESULTS.md +36 -0
- hermeneutic-0.1.7/evals/bucket-discrimination/results.json +39 -0
- hermeneutic-0.1.7/evals/bucket-discrimination/runner.py +257 -0
- hermeneutic-0.1.7/evals/compile-walkthrough.md +127 -0
- hermeneutic-0.1.7/evals/gate-coverage/RESULTS.md +45 -0
- hermeneutic-0.1.7/evals/gate-coverage/results.json +153 -0
- hermeneutic-0.1.7/evals/gate-coverage/runner.py +248 -0
- hermeneutic-0.1.7/evals/leave-one-out/RESULTS.md +39 -0
- hermeneutic-0.1.7/evals/leave-one-out/diagnose_minority.py +95 -0
- hermeneutic-0.1.7/evals/leave-one-out/results.json +143 -0
- hermeneutic-0.1.7/evals/leave-one-out/runner.py +310 -0
- hermeneutic-0.1.7/evals/leave-one-out/test_bucket_aware.py +110 -0
- hermeneutic-0.1.7/evals/self_test.sh +47 -0
- hermeneutic-0.1.7/evals/triple-mining-receipts.md +65 -0
- hermeneutic-0.1.7/examples/before_after.md +46 -0
- hermeneutic-0.1.7/forward-deployed/REPORT-TEMPLATE.md +52 -0
- hermeneutic-0.1.7/forward-deployed/boot.py +182 -0
- hermeneutic-0.1.7/forward-deployed/check_report.py +77 -0
- hermeneutic-0.1.7/forward-deployed/gate.py +179 -0
- hermeneutic-0.1.7/forward-deployed/harness.py +281 -0
- hermeneutic-0.1.7/forward-deployed/sentinel.py +171 -0
- hermeneutic-0.1.7/integrations/README.md +93 -0
- hermeneutic-0.1.7/integrations/claude-code.md +135 -0
- hermeneutic-0.1.7/integrations/cline.md +31 -0
- hermeneutic-0.1.7/integrations/codex.md +142 -0
- hermeneutic-0.1.7/integrations/cursor.md +50 -0
- hermeneutic-0.1.7/integrations/openhands.md +33 -0
- hermeneutic-0.1.7/integrations/windsurf.md +32 -0
- hermeneutic-0.1.7/llms.txt +67 -0
- hermeneutic-0.1.7/pyproject.toml +114 -0
- hermeneutic-0.1.7/sbom.cdx.json +47 -0
- hermeneutic-0.1.7/src/hermeneutic/__init__.py +21 -0
- hermeneutic-0.1.7/src/hermeneutic/cli.py +592 -0
- hermeneutic-0.1.7/src/hermeneutic/compile.py +319 -0
- hermeneutic-0.1.7/src/hermeneutic/gates/__init__.py +1 -0
- hermeneutic-0.1.7/src/hermeneutic/gates/regex.py +145 -0
- hermeneutic-0.1.7/src/hermeneutic/gates/rubric.py +85 -0
- hermeneutic-0.1.7/src/hermeneutic/gates/twin.py +128 -0
- hermeneutic-0.1.7/src/hermeneutic/harvest.py +229 -0
- hermeneutic-0.1.7/src/hermeneutic/install_hook.py +491 -0
- hermeneutic-0.1.7/src/hermeneutic/py.typed +1 -0
- hermeneutic-0.1.7/src/hermeneutic/router.py +130 -0
- hermeneutic-0.1.7/src/hermeneutic/telemetry.py +232 -0
- hermeneutic-0.1.7/src/hermeneutic/triples.py +281 -0
- hermeneutic-0.1.7/tests/__init__.py +0 -0
- hermeneutic-0.1.7/tests/test_cli.py +201 -0
- hermeneutic-0.1.7/tests/test_compile.py +539 -0
- hermeneutic-0.1.7/tests/test_docs_consistency.py +151 -0
- hermeneutic-0.1.7/tests/test_forward_deployed.py +302 -0
- hermeneutic-0.1.7/tests/test_harvest.py +241 -0
- hermeneutic-0.1.7/tests/test_install_hook.py +161 -0
- hermeneutic-0.1.7/tests/test_plugin_scripts.py +107 -0
- hermeneutic-0.1.7/tests/test_regex.py +86 -0
- hermeneutic-0.1.7/tests/test_router.py +67 -0
- hermeneutic-0.1.7/tests/test_telemetry.py +219 -0
- hermeneutic-0.1.7/tests/test_triples.py +139 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"upload_type": "software",
|
|
3
|
+
"title": "hermeneutic: local correction evidence, retrieval, and deterministic English drift checks",
|
|
4
|
+
"version": "0.1.7",
|
|
5
|
+
"description": "hermeneutic is a local-first Python toolkit that mines correction triples from supported AI chat logs, optionally retrieves similar prior corrections through a local Ollama-backed compiler, and runs eight fixed deterministic English surface checks on outgoing drafts. Mining personalizes the local corpus and retrieval; it does not rewrite the gate. A separate programmable Python Router can compose optional external rubric, model-critic, and repair callables. The project is a review aid and reliability floor, not proof of correctness. Its historical corpus and retrieval measurements are single-user, and downstream effectiveness has not been measured. Private triples and embeddings are not distributed.",
|
|
6
|
+
"creators": [
|
|
7
|
+
{ "name": "Bosch Rodriguez, Rolando", "orcid": "0009-0005-4896-1112", "affiliation": "Hermes Labs" }
|
|
8
|
+
],
|
|
9
|
+
"keywords": [
|
|
10
|
+
"AI reliability",
|
|
11
|
+
"LLM reliability",
|
|
12
|
+
"silent failure modes",
|
|
13
|
+
"evidence-first",
|
|
14
|
+
"hermeneutic drift",
|
|
15
|
+
"correction mining",
|
|
16
|
+
"pre-flight gate",
|
|
17
|
+
"post-completion overclaiming"
|
|
18
|
+
],
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"related_identifiers": [
|
|
21
|
+
{ "identifier": "10.5281/zenodo.20471023", "relation": "isVersionOf", "scheme": "doi" },
|
|
22
|
+
{ "identifier": "10.5281/zenodo.19042469", "relation": "references", "scheme": "doi" }
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# AGENTS.md — using hermeneutic from a coding agent
|
|
2
|
+
|
|
3
|
+
This file is for AI coding agents and host applications that want to call the
|
|
4
|
+
standalone `hermeneutic` CLI or Python library.
|
|
5
|
+
|
|
6
|
+
## What this tool does
|
|
7
|
+
|
|
8
|
+
A fixed deterministic English drift check for assistant-generated drafts. It
|
|
9
|
+
flags eight surface shapes including completion overclaiming, relayed authority,
|
|
10
|
+
unhedged certainty, scope expansion, and unsupported quality adjectives. It
|
|
11
|
+
does not read the personal correction corpus or run the optional Router.
|
|
12
|
+
|
|
13
|
+
## When to invoke it
|
|
14
|
+
|
|
15
|
+
Run `hermeneutic gate` on any assistant draft *before* you send it to the user
|
|
16
|
+
when:
|
|
17
|
+
|
|
18
|
+
- The draft contains numeric claims (file counts, test counts, percentages, ms).
|
|
19
|
+
- The draft summarizes work completed by a subagent.
|
|
20
|
+
- The draft uses completion language ("done", "shipped", "all green").
|
|
21
|
+
- The draft contains universal quantifiers ("every", "all", "always").
|
|
22
|
+
- You want a cheap second-opinion gate that doesn't require an LLM call.
|
|
23
|
+
|
|
24
|
+
Inspect the printed verdict as well as the exit code: low-severity `RISK` is
|
|
25
|
+
advisory and exits 0; medium/high `RISK` exits 1. A caller that chooses to hold a
|
|
26
|
+
draft should either:
|
|
27
|
+
1. Add the missing evidence (run the verification commands, paste the output).
|
|
28
|
+
2. Hedge the claim ("appears to" / "based on N samples").
|
|
29
|
+
3. Cut the unverifiable text.
|
|
30
|
+
|
|
31
|
+
## Programmatic use
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
from hermeneutic import Router, PressureProbe
|
|
35
|
+
|
|
36
|
+
probe = PressureProbe(judge=your_llm_call) # callable: prompt -> str
|
|
37
|
+
|
|
38
|
+
def repair(request, draft, reason):
|
|
39
|
+
return your_llm_call(f"Revise: {reason}\n\n{draft}")
|
|
40
|
+
|
|
41
|
+
router = Router(probe=probe, repairer=repair)
|
|
42
|
+
result = router.gate(request=user_request, draft=your_draft)
|
|
43
|
+
if result.repaired:
|
|
44
|
+
log(f"hermeneutic caught drift: {result.summary()}")
|
|
45
|
+
final = result.final_output
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Calibration
|
|
49
|
+
|
|
50
|
+
`PressureProbe` ships with a generic "rigorous-skeptic" calibration. To make it
|
|
51
|
+
match your team's standards, pass your own calibration text:
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
my_calibration = """
|
|
55
|
+
You are reviewing drafts for a security-critical product.
|
|
56
|
+
Bias toward HOLD when:
|
|
57
|
+
- Any security claim lacks a CVE or vendor-confirmed citation.
|
|
58
|
+
- Code changes touch authentication or crypto without a test diff.
|
|
59
|
+
"""
|
|
60
|
+
probe = PressureProbe(judge=your_llm_call, calibration=my_calibration)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Mining your own logs
|
|
64
|
+
|
|
65
|
+
Mine your own chat logs to build a personal corpus and look for candidate drift
|
|
66
|
+
modes:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
hermeneutic mine ~/your/log/dir --format claude-code --out triples.jsonl
|
|
70
|
+
hermeneutic bucket triples.jsonl
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Mining does not change the gate. A developer may deliberately add a new pattern
|
|
74
|
+
to `src/hermeneutic/gates/regex.py` only with evidence, tests, review, and a new
|
|
75
|
+
release. The personal corpus can affect optional compile retrieval after
|
|
76
|
+
`compile-index` is rerun.
|
|
77
|
+
|
|
78
|
+
## What this tool is NOT
|
|
79
|
+
|
|
80
|
+
- Not a model evaluator. Scores individual drafts, not aggregate quality.
|
|
81
|
+
- Not foresight. Catches drift modes seen before; novel drifts pass through.
|
|
82
|
+
- Not a replacement for human review. It's a floor-raiser.
|
|
83
|
+
- Not multilingual. The fixed rules check English surface patterns.
|
|
84
|
+
- Not proof that a caller's external Router backends or repair behavior are safe.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# BACKLOG
|
|
2
|
+
|
|
3
|
+
New ideas land here, not in new files. Nothing below is scheduled.
|
|
4
|
+
|
|
5
|
+
- **Assertion-granularity citation system** (queued 2026-04-28) — each claim
|
|
6
|
+
in compiled output should map to a specific triple-id in the corpus.
|
|
7
|
+
Currently the compile-hook injects a per-bucket steer summary; a future
|
|
8
|
+
enhancement adds `[evidence: triple-id-N]` markers per claim so outputs
|
|
9
|
+
cite specific past corrections at sentence level. Composes with
|
|
10
|
+
hermes-rubric's evidence-first scoring at finer granularity. Origin:
|
|
11
|
+
external feedback on the compile-preamble in action.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to Hermeneutic are documented here. The project follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
4
|
+
|
|
5
|
+
## [0.1.7] — Unreleased
|
|
6
|
+
|
|
7
|
+
### Publication truth corrections
|
|
8
|
+
|
|
9
|
+
- Reframed the product around its actual distinct surfaces: personal correction mining, optional personal retrieval, a fixed deterministic English gate, and a separately configured Python Router.
|
|
10
|
+
- Replaced the Claude compile hook's user-visible `systemMessage` with the documented `UserPromptSubmit` `hookSpecificOutput.additionalContext` contract. The installer now registers an exec-form command bound to the running Python interpreter, handles paths with spaces, migrates or cleans its exact legacy registration, preserves unrelated hooks, and avoids destructive malformed-settings behavior.
|
|
11
|
+
- Added exact compile-hook contract coverage for success JSON, empty/missing results, unavailable Ollama, malformed input/state, compiler failures, timeouts, idempotency, foreign-file protection, legacy cleanup, coexistence, and uninstall.
|
|
12
|
+
- Replaced the leave-one-out evaluator's duplicated selection approximation with calls through the shipped `compile_prompt()` production path. Current same-bucket results on the frozen 346-triple corpus are 88/104 (84.6%) at CLI/hook defaults and 94/104 (90.4%) at Python defaults.
|
|
13
|
+
- Added a privacy-safe current gate-coverage receipt: 115/346 (33.24%) prior assistant replies in the frozen correction corpus fire at least one current rule. This is retrospective derivation-set coverage, not held-out accuracy.
|
|
14
|
+
- Moved the prior 83.7% leave-one-out and 98/100 discrimination figures into historical-only framing because their evaluators did not match the shipped selection path.
|
|
15
|
+
- Classified every integration by evidence maturity. The Claude compile hook, Codex plugin mechanics, and forward-deployed tooling are mechanically tested; Cursor/OpenHands are design sketches; current Claude Stop, Cline, and Windsurf adapters are removed from the ready-support matrix.
|
|
16
|
+
- Synchronized README, package description, machine-readable summary, examples, theory/intent docs, citation metadata, Zenodo metadata, plugin descriptions, installation commands, optional dependencies, privacy boundaries, and author display.
|
|
17
|
+
|
|
18
|
+
### Added and hardened
|
|
19
|
+
|
|
20
|
+
- Eight fixed English stage-one rules with a partial-progress contrast guard.
|
|
21
|
+
- Correction mining for Claude Code, Codex rollout, and OpenAI-style message logs; loud zero-parse diagnostics; multi-directory input; nested output-directory creation.
|
|
22
|
+
- Optional local-Ollama compile index and deterministic bucket-aware warning preambles.
|
|
23
|
+
- Local opt-in telemetry, reviewable audit modes, `stats`, harvest classification, human review, and accepted-record promotion.
|
|
24
|
+
- Wheel-built Claude compile-hook installer plus repository/sdist standalone plugin assets and integration documentation.
|
|
25
|
+
- Forward-deployed environment/boot/harvest/report/gate tooling, report leak checks, tamper-evident mission state, and optional Codex notification sentinel.
|
|
26
|
+
- Trusted-publishing GitHub Actions workflow, wheel/sdist checks, exact-sdist tests, typed-package smoke, release metadata, and software citation files.
|
|
27
|
+
|
|
28
|
+
### Boundaries
|
|
29
|
+
|
|
30
|
+
- Core library and CLI have zero required Python runtime dependencies.
|
|
31
|
+
- Stage-one checks are fixed English surface patterns. Mining and promotion do not generate regex rules.
|
|
32
|
+
- Live Ollama, live response-hook hosts, external Router backends, Windows, false-positive rate on ordinary prompts, and downstream model effectiveness are not certified by this release.
|
|
33
|
+
- The wheel contains the core, CLI, type marker, and built-in hook installers. Evaluations, standalone plugins, integration docs, and forward-deployed tooling require the repository or extracted sdist.
|
|
34
|
+
|
|
35
|
+
## [0.1.6] — 2026-07-08
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
|
|
39
|
+
- Opt-in local JSONL gate/compile telemetry with context labels and best-effort failure isolation.
|
|
40
|
+
- Audit modes `none`, `hash`, and `raw`, plus draft fingerprints and matched-context windows.
|
|
41
|
+
- `stats`, `harvest`, `harvest --sanitized`, and `promote` review-loop commands.
|
|
42
|
+
- Codex rollout reader and forward-deployed validation tooling.
|
|
43
|
+
- Two additional fixed English rule shapes and a contrastive partial-progress guard, bringing the rule count to eight.
|
|
44
|
+
|
|
45
|
+
### Changed
|
|
46
|
+
|
|
47
|
+
- Declared the fixed gate's English-only boundary.
|
|
48
|
+
- Improved loud failure for missing inputs, unsupported log shapes, corrupt harness state, and invalid explicit session paths.
|
|
49
|
+
|
|
50
|
+
## [0.1.5+bucket-aware] — 2026-04-27
|
|
51
|
+
|
|
52
|
+
Local-only retrieval iteration on the v0.1.5 compiler. It introduced per-bucket selection and recorded the historical 83.7% leave-one-out and 98/100 versus 7/30 discrimination experiments. Those values remain provenance receipts, not current production-path claims; the original embedding artifact was not fully pinned and the evaluators later proved behaviorally different from `compile_prompt()`.
|
|
53
|
+
|
|
54
|
+
## [0.1.5] — 2026-04-26
|
|
55
|
+
|
|
56
|
+
### Added
|
|
57
|
+
|
|
58
|
+
- `orig_prompt` in correction triples with backward-compatible loading.
|
|
59
|
+
- Local Ollama `nomic-embed-text` index stored under `~/.hermeneutic/`.
|
|
60
|
+
- `compile-index`, `compile`, deterministic preamble synthesis, and an initial Claude prompt hook.
|
|
61
|
+
|
|
62
|
+
## [0.1.1] — 2026-04-26
|
|
63
|
+
|
|
64
|
+
### Added
|
|
65
|
+
|
|
66
|
+
- Additional log-reader resilience, CLI error reporting, and packaging metadata.
|
|
67
|
+
|
|
68
|
+
## [0.1.0] — 2026-04-25
|
|
69
|
+
|
|
70
|
+
### Added
|
|
71
|
+
|
|
72
|
+
- Correction-triple mining and bucketing.
|
|
73
|
+
- Fixed regex gate and programmable three-stage Router.
|
|
74
|
+
- Python library and `hermeneutic` CLI under the MIT License.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use hermeneutic, please cite it as below."
|
|
3
|
+
title: "hermeneutic: local correction evidence, retrieval, and deterministic English drift checks"
|
|
4
|
+
abstract: >-
|
|
5
|
+
hermeneutic is a local-first Python toolkit that mines correction triples from
|
|
6
|
+
supported AI chat logs, optionally retrieves similar prior corrections through
|
|
7
|
+
a local Ollama-backed compiler, and runs eight fixed deterministic English
|
|
8
|
+
surface checks on outgoing drafts. A separate programmable Python Router can
|
|
9
|
+
compose optional external rubric, model-critic, and repair callables. The tool
|
|
10
|
+
is a review aid and reliability floor, not proof of correctness. Historical
|
|
11
|
+
corpus and retrieval measurements are single-user, and downstream effectiveness
|
|
12
|
+
has not been measured.
|
|
13
|
+
type: software
|
|
14
|
+
version: "0.1.7"
|
|
15
|
+
authors:
|
|
16
|
+
- family-names: "Bosch Rodriguez"
|
|
17
|
+
given-names: "Rolando"
|
|
18
|
+
orcid: "https://orcid.org/0009-0005-4896-1112"
|
|
19
|
+
affiliation: "Hermes Labs"
|
|
20
|
+
email: roli@hermes-labs.ai
|
|
21
|
+
license: MIT
|
|
22
|
+
repository-code: "https://github.com/hermes-labs-ai/hermeneutic"
|
|
23
|
+
url: "https://hermes-labs.ai"
|
|
24
|
+
keywords:
|
|
25
|
+
- "AI reliability"
|
|
26
|
+
- "LLM reliability"
|
|
27
|
+
- "silent failure modes"
|
|
28
|
+
- "evidence-first"
|
|
29
|
+
- "hermeneutic drift"
|
|
30
|
+
- "correction mining"
|
|
31
|
+
- "pre-flight gate"
|
|
32
|
+
- "post-completion overclaiming"
|
|
33
|
+
references:
|
|
34
|
+
- type: article
|
|
35
|
+
title: "A Taxonomy of Epistemic Failure Modes in LLMs"
|
|
36
|
+
authors:
|
|
37
|
+
- family-names: "Bosch Rodriguez"
|
|
38
|
+
given-names: "Rolando"
|
|
39
|
+
doi: "10.5281/zenodo.19042469"
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# CLAUDE.md — working on hermeneutic
|
|
2
|
+
|
|
3
|
+
Read `AGENTS.md` first — it is the canonical in-session protocol for coding
|
|
4
|
+
agents using or modifying this repo, and everything there applies to Claude
|
|
5
|
+
Code sessions too.
|
|
6
|
+
|
|
7
|
+
Repo-specific rules for agents:
|
|
8
|
+
|
|
9
|
+
- **The core gate stays zero-LLM.** Never wire an LLM call into a default
|
|
10
|
+
path. The optional compiler defaults to localhost Ollama; Python callers can
|
|
11
|
+
override that URL, and caller-supplied Router components own their network
|
|
12
|
+
and credential behavior.
|
|
13
|
+
- **Every behavior change gets a test**, and the full suite must stay green:
|
|
14
|
+
`PYTHONPATH=src python -m pytest -q`. The README/CHANGELOG test count is
|
|
15
|
+
enforced by `tests/test_docs_consistency.py` — update all surfaces together.
|
|
16
|
+
- **Never loosen an existing gate rule to silence a false positive.** Note it
|
|
17
|
+
in the harvest queue instead; rule changes require mined evidence
|
|
18
|
+
(see `evals/triple-mining-receipts.md` for the bar).
|
|
19
|
+
- **Honest partial progress is not drift** — don't "improve" recall by
|
|
20
|
+
flagging "did X, but Y remains" (`_CONTRAST_GUARD` protects this; keep it).
|
|
21
|
+
- **Numbers in docs must trace to committed receipts** in `evals/`. No
|
|
22
|
+
uncommitted benchmark claims.
|
|
23
|
+
- Lint with `ruff check src tests` before committing.
|
|
24
|
+
|
|
25
|
+
To verify a deployment of this tool in your own environment, run the
|
|
26
|
+
forward-deployed harness: `python3 forward-deployed/harness.py` (see
|
|
27
|
+
`FORWARD-DEPLOYED-HARNESS.md`).
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Code of Conduct
|
|
2
|
+
|
|
3
|
+
This project follows the [Contributor Covenant v2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/).
|
|
4
|
+
|
|
5
|
+
By participating, you agree to uphold it. Report conduct concerns to `roli@hermes-labs.ai`; reports are handled confidentially.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in `hermeneutic`. This document describes how to propose changes.
|
|
4
|
+
|
|
5
|
+
## Scope
|
|
6
|
+
|
|
7
|
+
`hermeneutic` is a focused tool: it mines correction triples, optionally retrieves similar prior corrections, and runs a fixed English check over outgoing drafts. It is **not** a general-purpose evaluation framework, model benchmarker, or default LLM router for production traffic.
|
|
8
|
+
|
|
9
|
+
**In-scope:** new chat-log readers, new evidence-based risk patterns, calibration recipes for `PressureProbe`, bug fixes, docs, test coverage.
|
|
10
|
+
|
|
11
|
+
**Out-of-scope:**
|
|
12
|
+
|
|
13
|
+
- Aggregate model evaluation — use a benchmark suite.
|
|
14
|
+
- Static analysis of prompt scaffolds, which is outside this repository's scope.
|
|
15
|
+
- Agent-config structural analysis — that belongs in [lintlang](https://github.com/hermes-labs-ai/lintlang).
|
|
16
|
+
- Anything that adds a mandatory runtime dependency. Stage 2 (hermes-rubric) and stage 3 (your LLM) stay optional and pluggable.
|
|
17
|
+
|
|
18
|
+
Open an issue first if you're unsure.
|
|
19
|
+
|
|
20
|
+
## Development setup
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
git clone https://github.com/hermes-labs-ai/hermeneutic
|
|
24
|
+
cd hermeneutic
|
|
25
|
+
python3 -m venv .venv
|
|
26
|
+
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
27
|
+
python3 -m pip install -e ".[dev]"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Running the checks
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
python3 -m ruff check .
|
|
34
|
+
python3 -m pytest -ra
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
CI runs the same commands on Python 3.10–3.13.
|
|
38
|
+
|
|
39
|
+
## Adding a new risk pattern
|
|
40
|
+
|
|
41
|
+
Patterns must be **evidence-based**: derived from real corrections you've mined.
|
|
42
|
+
|
|
43
|
+
1. Add the pattern to `_RAW_PATTERNS` in `src/hermeneutic/gates/regex.py` with `(rule_id, severity, regex, description)`.
|
|
44
|
+
2. Add a test in `tests/test_regex.py` covering both a draft it should flag and one it should not.
|
|
45
|
+
3. In the PR description, include: how many corrections in your mined corpus matched this pattern, and a sanitized example.
|
|
46
|
+
4. Update `CHANGELOG.md` under `[Unreleased]`.
|
|
47
|
+
|
|
48
|
+
Severity guide: `high` = strong drift signal that almost always warrants a downstream check. `med` = often associated with drift but more false positives. `low` = stylistic tell only.
|
|
49
|
+
|
|
50
|
+
## Adding a new chat-log reader
|
|
51
|
+
|
|
52
|
+
1. Subclass `LogReader` in `src/hermeneutic/triples.py`.
|
|
53
|
+
2. Implement `iter_turns(path) -> Iterator[(role, text, timestamp)]`.
|
|
54
|
+
3. Register your reader in the `READERS` dict.
|
|
55
|
+
4. Add a round-trip test in `tests/test_triples.py`.
|
|
56
|
+
|
|
57
|
+
## Pull request checklist
|
|
58
|
+
|
|
59
|
+
- [ ] `ruff check .` passes
|
|
60
|
+
- [ ] `pytest -ra` passes
|
|
61
|
+
- [ ] No new mandatory runtime dependency added
|
|
62
|
+
- [ ] `CHANGELOG.md` updated under `[Unreleased]`
|
|
63
|
+
- [ ] New rules / readers have tests
|
|
64
|
+
- [ ] No backward-incompatible API change without a major-version bump
|
|
65
|
+
|
|
66
|
+
## Filing issues
|
|
67
|
+
|
|
68
|
+
Minimum useful report: Python version, OS, exact command, draft text (or a minimal reproducer), observed output, expected output.
|
|
69
|
+
|
|
70
|
+
For mining-related issues, please include a sanitized example log entry that reproduces the problem.
|
|
71
|
+
|
|
72
|
+
## Code of conduct
|
|
73
|
+
|
|
74
|
+
See [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md).
|
|
75
|
+
|
|
76
|
+
## License
|
|
77
|
+
|
|
78
|
+
By contributing, you agree that your contributions are licensed under the MIT License (see [LICENSE](LICENSE)).
|
|
79
|
+
|
|
80
|
+
## Pull request flow
|
|
81
|
+
|
|
82
|
+
Open a focused pull request against `main`. Keep unrelated changes separate,
|
|
83
|
+
make every behavior change executable by a test, and wait for the full CI
|
|
84
|
+
matrix—including the built-artifact job—to pass at the latest head SHA. Resolve
|
|
85
|
+
review conversations before merge. Repository settings, rather than this file,
|
|
86
|
+
are the authority for required checks and merge permissions.
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# FORWARD-DEPLOYED HARNESS — instructions for the agent that executes it
|
|
2
|
+
|
|
3
|
+
**This file is the instructions. The harness itself is executable** —
|
|
4
|
+
`forward-deployed/harness.py`, a deterministic step-machine that drives the
|
|
5
|
+
mission and verifies each step from artifacts before the next unlocks. You
|
|
6
|
+
read this once for context; you RUN the harness.
|
|
7
|
+
|
|
8
|
+
You are an agent reading this inside the adopter's environment — an
|
|
9
|
+
environment the author of this package cannot see and deliberately never
|
|
10
|
+
will. Read this whole file before acting. When you finish it, you are the
|
|
11
|
+
**forward-deployed engineer** for hermeneutic here: verify that it works in
|
|
12
|
+
this harness, adapt it where it doesn't, and leave behind a sanitized report
|
|
13
|
+
of what you did. You know this environment better than the author ever
|
|
14
|
+
could — that asymmetry is the design, not a workaround.
|
|
15
|
+
|
|
16
|
+
## The concept (60 seconds)
|
|
17
|
+
|
|
18
|
+
Every chat log contains a discarded dataset: the moments the user corrected
|
|
19
|
+
the assistant — *"no, not that"*, *"still crashes"*, *"I said MySQL"*. Each
|
|
20
|
+
correction marks a drift: the assistant did Y when asked for X, did half and
|
|
21
|
+
called it done, or overclaimed ("Done — 14 files, all green") without the
|
|
22
|
+
receipts. hermeneutic mines those corrections into `(drift, steer, repair)`
|
|
23
|
+
triples and uses them twice:
|
|
24
|
+
|
|
25
|
+
1. **The gate** (`hermeneutic gate`) — a zero-LLM regex tripwire run on
|
|
26
|
+
outgoing drafts. It catches announcement-shaped drift modes with a local,
|
|
27
|
+
deterministic regex pass; every fire is explainable. It is a floor, not a
|
|
28
|
+
guarantee.
|
|
29
|
+
2. **The compile layer** (`hermeneutic compile`) — optionally retrieves past
|
|
30
|
+
corrections similar to the incoming prompt and prints a "watch out for X"
|
|
31
|
+
preamble for a caller or supported context hook to inject.
|
|
32
|
+
|
|
33
|
+
## The map (what lives where)
|
|
34
|
+
|
|
35
|
+
| Path | What it is |
|
|
36
|
+
|---|---|
|
|
37
|
+
| `src/hermeneutic/gates/regex.py` | the 8 canonical rules — the gate itself |
|
|
38
|
+
| `src/hermeneutic/triples.py` | log readers (`claude-code`, `codex`, `openai` — registered in `READERS`) + the miner |
|
|
39
|
+
| `src/hermeneutic/harvest.py` | replay-classify loop (`confirmed_catch` / `possible_false_positive` / `missed_drift`), `promote`, sanitized output |
|
|
40
|
+
| `src/hermeneutic/compile.py` | embeddings (local Ollama, `nomic-embed-text`) + preamble builder |
|
|
41
|
+
| `src/hermeneutic/cli.py` | every command |
|
|
42
|
+
| `evals/` | self-test, current bounded receipts, and clearly labeled historical experiments |
|
|
43
|
+
| `tests/` | the suite — `python -m pytest -q` must stay green |
|
|
44
|
+
| `AGENTS.md` | the in-session protocol; meant to be copied into the human's own projects' `AGENTS.md` |
|
|
45
|
+
|
|
46
|
+
## Invariants — never break these, whatever you change
|
|
47
|
+
|
|
48
|
+
1. **The core gate stays zero-LLM.** Deterministic and local, every fire
|
|
49
|
+
explainable by pointing at a rule and matched text. No LLM call on any
|
|
50
|
+
default path, ever.
|
|
51
|
+
2. **Privacy is structural.** Nothing leaves this machine by default.
|
|
52
|
+
Anything labeled sanitized carries zero message text — counts, rule ids,
|
|
53
|
+
timestamps, hashes, lengths only. That is data minimization, not proof of
|
|
54
|
+
anonymity; a human reviews the metadata before sharing it.
|
|
55
|
+
3. **Tense is load-bearing** in the rules: past-tense completion claims
|
|
56
|
+
gate, planned future work does not. Naive stemming destroys the
|
|
57
|
+
distinction.
|
|
58
|
+
4. **Honest partial progress is not drift.** Never "improve" recall by
|
|
59
|
+
flagging "did X, but Y remains".
|
|
60
|
+
5. **Fail loud.** Zero-parse must exit 2 with an explanation, never emit
|
|
61
|
+
silent zero output.
|
|
62
|
+
6. **Tests and evals gate every change.** The full suite green after every
|
|
63
|
+
edit; every behavior you add gets a test.
|
|
64
|
+
|
|
65
|
+
## THE PROTOCOL — the harness drives, you execute
|
|
66
|
+
|
|
67
|
+
The mission is not self-reported. It is driven by a step-machine:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
python3 forward-deployed/harness.py
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Run it. Do exactly what it prints. Run it again. Repeat until it prints
|
|
74
|
+
**MISSION COMPLETE** with an attestation hash. Each step (ENV → BOOT →
|
|
75
|
+
HARVEST → REPORT → GATE) is verified mechanically from artifacts on disk
|
|
76
|
+
before the next unlocks — described-but-not-done work does not advance the
|
|
77
|
+
mission. Progress is a hash chain in `forward-deployed/mission-state.json`
|
|
78
|
+
(`python3 forward-deployed/harness.py verify` audits it). Honest scope: the
|
|
79
|
+
chain is tamper-evident against sloppy or accidental edits, not cryptographic
|
|
80
|
+
proof — a determined forger can recompute it. The attestation is a receipt
|
|
81
|
+
that disciplined work happened in order; what your human reviews and sends
|
|
82
|
+
is the report and artifacts, not the hash alone.
|
|
83
|
+
|
|
84
|
+
The sections below are your reference material for the steps the harness
|
|
85
|
+
will hand you.
|
|
86
|
+
|
|
87
|
+
## BOOT — what the harness runs first (~2 minutes)
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
python3 -m pip install -e '.[dev]' # once — pytest ships in the dev extra, boot needs it
|
|
91
|
+
python3 forward-deployed/boot.py # add --sessions DIR --format X if logs live elsewhere
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
It runs the whole verification sequence — test suite, gate self-test, the
|
|
95
|
+
gate smoke trio against documented expectations, and a
|
|
96
|
+
sanitized harvest probe over real logs — and writes
|
|
97
|
+
`forward-deployed/boot-report.json` (sanitized by construction; out-of-repo
|
|
98
|
+
paths are stripped before anything is stored). **Exit 0 / `fits-as-shipped`:**
|
|
99
|
+
all package-controlled checks passed; if no matching logs existed, the
|
|
100
|
+
real-log probe is labeled `not_exercised` rather than fabricated as a pass.
|
|
101
|
+
Tell your human, run the real sanitized harvest for them — write it to the
|
|
102
|
+
gitignored `build/` dir (e.g. `--out build/report.jsonl`) so the tree stays
|
|
103
|
+
pristine, and leave `promote` to your human unless they ask — then write the
|
|
104
|
+
report (below). **Exit 1 / `adaptation-needed`:** the failed steps are your work
|
|
105
|
+
queue, in the order they appear.
|
|
106
|
+
|
|
107
|
+
Manual equivalents, when you need to investigate a failure directly:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
python3 -m pytest -q # expect: all green, 0 failed
|
|
111
|
+
bash evals/self_test.sh # expect: PASS
|
|
112
|
+
echo "Done — shipped 14 files, all tests pass." | hermeneutic gate # → RISK
|
|
113
|
+
echo "Fixed 3 of the 14 failing tests; 11 still fail." | hermeneutic gate # → PASS (honest partial progress)
|
|
114
|
+
echo "I will ship the remaining files tomorrow." | hermeneutic gate # → PASS (a plan is not a claim)
|
|
115
|
+
hermeneutic harvest ~/.claude/projects --format claude-code --sanitized --out /tmp/hh-probe.jsonl
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Permitted adaptations (most likely first)
|
|
119
|
+
|
|
120
|
+
- **A. Log format mismatch** (harvest says ZERO EVENTS on real logs):
|
|
121
|
+
subclass `LogReader` in `triples.py`, register it in `READERS`. Verify
|
|
122
|
+
against ONE real session file, then add a test using synthetic fixture
|
|
123
|
+
data only — never commit real log content.
|
|
124
|
+
- **B. Rule gaps** (drift your human corrects that the gate misses): add a
|
|
125
|
+
bounded-window rule to `gates/regex.py` following the existing tuple
|
|
126
|
+
pattern, with the mined evidence that justifies it and a test. Add rules,
|
|
127
|
+
never loosen existing ones.
|
|
128
|
+
- **C. Correction-marker gaps** (real corrections invisible to the miner):
|
|
129
|
+
extend the correction markers in `triples.py` the same way.
|
|
130
|
+
- **D. Path and layout differences**: prefer `--glob` flags over code edits.
|
|
131
|
+
- **E. Architectural adaptation**: allowed when A–D don't fit, if every
|
|
132
|
+
invariant holds and tests + evals stay green. Prefer additive changes
|
|
133
|
+
behind a flag. You are expected to harden this beyond what its author
|
|
134
|
+
could do blind — that is the assignment, not an exception.
|
|
135
|
+
|
|
136
|
+
**Do not**: wire an LLM into a default path; weaken completion rules
|
|
137
|
+
globally to silence a known false-fire (note occurrences in your report
|
|
138
|
+
instead — rule changes need their own mined evidence); put any session
|
|
139
|
+
text, out-of-repo path, or personal identifier in anything you commit or
|
|
140
|
+
report.
|
|
141
|
+
|
|
142
|
+
## The report you leave behind
|
|
143
|
+
|
|
144
|
+
Copy `forward-deployed/REPORT-TEMPLATE.md` to `FORWARD-DEPLOYED-REPORT.md`
|
|
145
|
+
at the repo root and fill it in. It is sanitized by the same rule as
|
|
146
|
+
`--sanitized`: **counts, categories, and this repo's own code — never your
|
|
147
|
+
human's text.** The linter checks common leak shapes (paths, identifiers, long
|
|
148
|
+
quotes, long Hangul runs); it is deliberately not presented as an exhaustive
|
|
149
|
+
privacy or anonymity check. English prose and organization-specific identifiers
|
|
150
|
+
may evade it, so human review completes the process. Before handing the report over, run it and
|
|
151
|
+
resolve every flag:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
python3 forward-deployed/check_report.py FORWARD-DEPLOYED-REPORT.md # must print CLEAN
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Structure:
|
|
158
|
+
|
|
159
|
+
1. **Environment** (categories only): OS family, Python `x.y`, package
|
|
160
|
+
version, agent CLI + version (Claude Code / Codex / other).
|
|
161
|
+
2. **Boot results**: pass/fail per step; for failures, exception type +
|
|
162
|
+
message with every out-of-repo path stripped.
|
|
163
|
+
3. **Adaptations**: per change — file, one-sentence reason (no session
|
|
164
|
+
content), the diff of THIS repo's code, tests added, and
|
|
165
|
+
`pytest` numbers before and after.
|
|
166
|
+
4. **Observed but not fixed**: known-false-fire counts, missed-drift shapes
|
|
167
|
+
described generically ("uncommon completion verb, casual register") —
|
|
168
|
+
never quoted.
|
|
169
|
+
5. **Open questions** for the author.
|
|
170
|
+
|
|
171
|
+
Your human reviews the report and sends it to roli@hermes-labs.ai. Nothing
|
|
172
|
+
sends itself; you have no network duties.
|
|
173
|
+
|
|
174
|
+
## Definition of package-controlled completion
|
|
175
|
+
|
|
176
|
+
The harness can establish that its package-controlled checks completed; it
|
|
177
|
+
cannot by itself establish that Hermeneutic is deployed and working on real
|
|
178
|
+
adopter logs. `gate.py` exit 0 closes the local verification chain with an
|
|
179
|
+
attestation:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
python3 forward-deployed/gate.py # exit 0 = package-controlled checks complete
|
|
183
|
+
python3 forward-deployed/harness.py # advances to MISSION COMPLETE + attestation
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
It deterministically checks: boot evidence fresh and `fits-as-shipped`,
|
|
187
|
+
the test suite green **in this environment**, the zero-LLM and privacy
|
|
188
|
+
invariants mechanically intact, and the report present and
|
|
189
|
+
`check_report.py`-CLEAN — always: "no adaptations needed" is a valid report,
|
|
190
|
+
a skipped one is not. If the gate says NOT DONE, it lists
|
|
191
|
+
exactly what's missing; finish that, don't argue with it. Treat `MISSION
|
|
192
|
+
COMPLETE` as the harness's internal completion state. A live deployment claim
|
|
193
|
+
additionally needs a human-reviewed real-log/adopter receipt; `not_exercised`
|
|
194
|
+
is never evidence of live fit. (Yes: the drift gate ships with a drift gate for
|
|
195
|
+
its own verification chain.)
|
|
196
|
+
|
|
197
|
+
## Runtime sentinel (optional, human-consented)
|
|
198
|
+
|
|
199
|
+
After MISSION COMPLETE, offer your human one more layer — enforcement that
|
|
200
|
+
lives inside Codex's own loop, via its native `notify` (turn-ended) hook:
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
python3 forward-deployed/sentinel.py install # reversible: sentinel.py uninstall
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
While any future mission is incomplete, a turn that *sounds* finished
|
|
207
|
+
triggers a desktop nudge ("harness says NOT DONE — next step: X"); and every
|
|
208
|
+
turn's last message is live-gated (zero-LLM, advisory — rule
|
|
209
|
+
ids only, never text). Install REFUSES if another notify hook exists (it
|
|
210
|
+
prints how to compose them by hand) and backs the config up first. This is
|
|
211
|
+
an explicit human decision — never install it silently.
|
|
212
|
+
|
|
213
|
+
## Escalation
|
|
214
|
+
|
|
215
|
+
If BOOT fails at the test suite or self-test stage, the defect is in the
|
|
216
|
+
package, not your environment: stop adapting, produce the diagnostic block
|
|
217
|
+
from `AGENTS.md` ("If something doesn't fit this harness") plus the report,
|
|
218
|
+
and have your human send both. That is a bug on the author's side and gets
|
|
219
|
+
fixed at the source.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Hermeneutic intent
|
|
2
|
+
|
|
3
|
+
Hermeneutic makes user corrections reusable without pretending that one mechanism does every job.
|
|
4
|
+
|
|
5
|
+
## Public surfaces
|
|
6
|
+
|
|
7
|
+
1. **Mine and bucket:** supported local chat logs become correction triples and aggregate categories.
|
|
8
|
+
2. **Compile and retrieve:** an optional local Ollama embedding index retrieves relevant prior corrections and renders a deterministic prompt preamble.
|
|
9
|
+
3. **Deterministic gate:** eight fixed English regex rules check outgoing text. Mining does not rewrite them.
|
|
10
|
+
4. **Programmable Router:** callers may compose the fixed gate with an optional `hermes-rubric` executable, a caller-supplied `PressureProbe`, and a caller-supplied repairer.
|
|
11
|
+
5. **Audit and review:** opt-in local telemetry plus harvest/review/promote mechanics create a reviewable correction loop.
|
|
12
|
+
|
|
13
|
+
## Accepts
|
|
14
|
+
|
|
15
|
+
- Transparent local evidence and deterministic behavior where possible.
|
|
16
|
+
- Personalization in the corpus and retrieval layer.
|
|
17
|
+
- Explicit caller ownership of blocking, external providers, repair policy, privacy, latency, and cost.
|
|
18
|
+
- New fixed gate rules only when a code change includes evidence, tests, and review.
|
|
19
|
+
|
|
20
|
+
## Refuses
|
|
21
|
+
|
|
22
|
+
- No claim that the gate writes itself.
|
|
23
|
+
- No claim that a `PASS` proves correctness or that a hook prevents every response.
|
|
24
|
+
- No multilingual claim; the fixed gate is English-only.
|
|
25
|
+
- No default model-evaluation, moderation, security-boundary, or factuality guarantee.
|
|
26
|
+
- No downstream-effectiveness claim without a direct measurement.
|
|
27
|
+
|
|
28
|
+
## Evidence boundary
|
|
29
|
+
|
|
30
|
+
The historical derivation receipt covers 326 corrections from 1,423 sessions belonging to one heavy user. A separate later frozen 346-triple corpus supports current aggregate gate and retrieval measurements, but neither corpus is a representative multi-user benchmark. Private triples are not distributed.
|
|
31
|
+
|
|
32
|
+
Current direct gate coverage on the frozen 346-triple corpus is 115/346 (33.24%). Current production-path same-bucket retrieval is 88/104 (84.6%) at CLI/hook defaults and 94/104 (90.4%) at Python defaults. These are single-corpus mechanism measurements, not precision, generalization, or evidence that a model follows the warning.
|
|
33
|
+
|
|
34
|
+
The project raises a review floor. Human and domain review remain responsible for the ceiling.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Hermes Labs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|