bensz-skill-kernel 0.14.1__py3-none-any.whl

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.
Files changed (55) hide show
  1. bensz_skill_kernel/__init__.py +159 -0
  2. bensz_skill_kernel/atomic_verifiers.py +93 -0
  3. bensz_skill_kernel/builtins.py +114 -0
  4. bensz_skill_kernel/cli.py +640 -0
  5. bensz_skill_kernel/contract_packs.py +864 -0
  6. bensz_skill_kernel/contracts.py +121 -0
  7. bensz_skill_kernel/packs.py +215 -0
  8. bensz_skill_kernel/runtime.py +1090 -0
  9. bensz_skill_kernel/state_ids.py +39 -0
  10. bensz_skill_kernel/states/active/STATE.md +42 -0
  11. bensz_skill_kernel/states/cancelled/STATE.md +32 -0
  12. bensz_skill_kernel/states/checking/STATE.md +45 -0
  13. bensz_skill_kernel/states/completed/STATE.md +35 -0
  14. bensz_skill_kernel/states/delivering/STATE.md +43 -0
  15. bensz_skill_kernel/states/failed/STATE.md +33 -0
  16. bensz_skill_kernel/states/index.json +16 -0
  17. bensz_skill_kernel/states/planned/STATE.md +41 -0
  18. bensz_skill_kernel/states/waiting/STATE.md +41 -0
  19. bensz_skill_kernel/states/workspace-closed/STATE.md +37 -0
  20. bensz_skill_kernel/states/workspace-ready/STATE.md +42 -0
  21. bensz_skill_kernel/states.py +706 -0
  22. bensz_skill_kernel/verifier_ids.py +34 -0
  23. bensz_skill_kernel/verifiers/artifact-file-exists/VERIFIER.md +4 -0
  24. bensz_skill_kernel/verifiers/artifact-file-exists/scripts/verify.py +24 -0
  25. bensz_skill_kernel/verifiers/citation-truth-and-fit/VERIFIER.md +6 -0
  26. bensz_skill_kernel/verifiers/contract-conformance/VERIFIER.md +3 -0
  27. bensz_skill_kernel/verifiers/contract-conformance/scripts/verify.py +5 -0
  28. bensz_skill_kernel/verifiers/diff-scope/VERIFIER.md +3 -0
  29. bensz_skill_kernel/verifiers/diff-scope/scripts/verify.py +5 -0
  30. bensz_skill_kernel/verifiers/event-integrity/VERIFIER.md +3 -0
  31. bensz_skill_kernel/verifiers/event-integrity/scripts/verify.py +5 -0
  32. bensz_skill_kernel/verifiers/evidence-provenance/VERIFIER.md +3 -0
  33. bensz_skill_kernel/verifiers/evidence-provenance/scripts/verify.py +5 -0
  34. bensz_skill_kernel/verifiers/index.json +18 -0
  35. bensz_skill_kernel/verifiers/markdown-link-integrity/VERIFIER.md +8 -0
  36. bensz_skill_kernel/verifiers/markdown-link-integrity/scripts/collector.py +261 -0
  37. bensz_skill_kernel/verifiers/markdown-link-integrity/scripts/verify.py +47 -0
  38. bensz_skill_kernel/verifiers/path-scope/VERIFIER.md +3 -0
  39. bensz_skill_kernel/verifiers/path-scope/scripts/verify.py +5 -0
  40. bensz_skill_kernel/verifiers/schema-conformance/VERIFIER.md +3 -0
  41. bensz_skill_kernel/verifiers/schema-conformance/scripts/verify.py +5 -0
  42. bensz_skill_kernel/verifiers/secret-redaction/VERIFIER.md +3 -0
  43. bensz_skill_kernel/verifiers/secret-redaction/scripts/verify.py +5 -0
  44. bensz_skill_kernel/verifiers/state-transition/VERIFIER.md +3 -0
  45. bensz_skill_kernel/verifiers/state-transition/scripts/verify.py +5 -0
  46. bensz_skill_kernel/verifiers/task-completeness/VERIFIER.md +3 -0
  47. bensz_skill_kernel/verifiers/task-completeness/scripts/verify.py +5 -0
  48. bensz_skill_kernel/verifiers.py +896 -0
  49. bensz_skill_kernel/workspace.py +269 -0
  50. bensz_skill_kernel-0.14.1.dist-info/METADATA +159 -0
  51. bensz_skill_kernel-0.14.1.dist-info/RECORD +55 -0
  52. bensz_skill_kernel-0.14.1.dist-info/WHEEL +5 -0
  53. bensz_skill_kernel-0.14.1.dist-info/entry_points.txt +2 -0
  54. bensz_skill_kernel-0.14.1.dist-info/licenses/LICENSE +21 -0
  55. bensz_skill_kernel-0.14.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,159 @@
1
+ """Minimal, append-only runtime kernel for Agent Skill task lifecycles."""
2
+
3
+ from .runtime import (
4
+ CompletionError,
5
+ EventEnvelope,
6
+ EventLog,
7
+ IntegrityError,
8
+ IdempotencyConflict,
9
+ AuthorizationError,
10
+ InvalidTransition,
11
+ KernelError,
12
+ VALID_STATES,
13
+ reduce_events,
14
+ )
15
+ from .contracts import Artifact, Authorization, Contract, Effect, Requirement, Subject, RUNTIME_PROTOCOL_VERSION
16
+ from .contract_packs import (
17
+ COMPONENT_RESULT_PROTOCOL,
18
+ CONTRACT_EXECUTION_PROTOCOL,
19
+ ComponentHandoff,
20
+ ComponentResult,
21
+ ContractBindingError,
22
+ ContractComponent,
23
+ ContractExecutionError,
24
+ ContractExecutionReport,
25
+ ContractPack,
26
+ ContractPackExecutor,
27
+ )
28
+ from .verifiers import (
29
+ Evidence,
30
+ CombinedVerifierRegistry,
31
+ FilesystemVerifierRegistry,
32
+ GateDecision,
33
+ PackRegistry,
34
+ VerifierPack,
35
+ VerifierRunner,
36
+ VerifierSpec,
37
+ VerifierDefinition,
38
+ VerifierRegistry,
39
+ VerificationRequest,
40
+ VerificationResult,
41
+ VerifierContractAdapter,
42
+ VerifierContractExecution,
43
+ apply_gate,
44
+ builtin_verifier_root,
45
+ normalize_result,
46
+ snapshot_evidence,
47
+ summarize_metrics,
48
+ normalize_requirements,
49
+ )
50
+ from .builtins import CITATION_TRUTH_FIT_SPEC, FILE_SPEC, build_builtin_registry, collect_markdown
51
+ from .verifier_ids import validate_verifier_id
52
+ from .state_ids import validate_state_id
53
+ from .states import CombinedStateRegistry, FilesystemStateRegistry, META_STATE_PROTOCOL_VERSION, SKILL_STATE_DECLARATION_VERSION, SkillStateDeclaration, StateContractAdapter, StateDefinition, StateDefinitionError, StateExecutionError, StateExecutionResult, StateTransitionError, StateMachine, build_builtin_state_registry, build_state_registry, check_state_invariants, execute_state
54
+ from .workspace import META_STATE_SNAPSHOT_VERSION, TaskWorkspace, WorkspaceError, WorkspacePaths, WORKSPACE_KINDS, WORKSPACE_PROTOCOL_VERSION, state_snapshot_hash, workspace_path
55
+
56
+ __all__ = [
57
+ "CompletionError",
58
+ "EventEnvelope",
59
+ "EventLog",
60
+ "IntegrityError",
61
+ "IdempotencyConflict",
62
+ "AuthorizationError",
63
+ "InvalidTransition",
64
+ "KernelError",
65
+ "VALID_STATES",
66
+ "reduce_events",
67
+ "Artifact",
68
+ "Authorization",
69
+ "Contract",
70
+ "Effect",
71
+ "Requirement",
72
+ "Subject",
73
+ "RUNTIME_PROTOCOL_VERSION",
74
+ "COMPONENT_RESULT_PROTOCOL",
75
+ "CONTRACT_EXECUTION_PROTOCOL",
76
+ "ComponentHandoff",
77
+ "ComponentResult",
78
+ "ContractBindingError",
79
+ "ContractComponent",
80
+ "ContractExecutionError",
81
+ "ContractExecutionReport",
82
+ "ContractPack",
83
+ "ContractPackExecutor",
84
+ "Evidence",
85
+ "CombinedVerifierRegistry",
86
+ "FilesystemVerifierRegistry",
87
+ "VerifierRegistry",
88
+ "GateDecision",
89
+ "PackRegistry",
90
+ "VerifierPack",
91
+ "VerifierRunner",
92
+ "VerifierSpec",
93
+ "VerifierDefinition",
94
+ "VerificationRequest",
95
+ "VerificationResult",
96
+ "VerifierContractAdapter",
97
+ "VerifierContractExecution",
98
+ "apply_gate",
99
+ "builtin_verifier_root",
100
+ "normalize_result",
101
+ "snapshot_evidence",
102
+ "summarize_metrics",
103
+ "normalize_requirements",
104
+ "CITATION_TRUTH_FIT_SPEC",
105
+ "FILE_SPEC",
106
+ "build_builtin_registry",
107
+ "collect_markdown",
108
+ "validate_verifier_id",
109
+ "validate_state_id",
110
+ "FilesystemStateRegistry",
111
+ "CombinedStateRegistry",
112
+ "META_STATE_PROTOCOL_VERSION",
113
+ "SKILL_STATE_DECLARATION_VERSION",
114
+ "SkillStateDeclaration",
115
+ "StateDefinition",
116
+ "StateContractAdapter",
117
+ "StateDefinitionError",
118
+ "StateExecutionError",
119
+ "StateExecutionResult",
120
+ "StateTransitionError",
121
+ "StateMachine",
122
+ "build_builtin_state_registry",
123
+ "build_state_registry",
124
+ "execute_state",
125
+ "check_state_invariants",
126
+ "TaskWorkspace",
127
+ "WorkspaceError",
128
+ "WorkspacePaths",
129
+ "WORKSPACE_KINDS",
130
+ "WORKSPACE_PROTOCOL_VERSION",
131
+ "META_STATE_SNAPSHOT_VERSION",
132
+ "workspace_path",
133
+ "state_snapshot_hash",
134
+ ]
135
+
136
+ def _distribution_version() -> str:
137
+ """Resolve the runtime version from the source metadata or installed wheel."""
138
+ from pathlib import Path
139
+ import importlib.metadata
140
+ import re
141
+
142
+ # During source-tree execution package metadata may describe an older
143
+ # globally installed wheel. Prefer the adjacent pyproject as the source
144
+ # of truth in that case.
145
+ pyproject = Path(__file__).resolve().parents[2] / "pyproject.toml"
146
+ try:
147
+ text = pyproject.read_text(encoding="utf-8")
148
+ match = re.search(r"(?m)^version\s*=\s*['\"]([^'\"]+)['\"]", text)
149
+ if match:
150
+ return match.group(1)
151
+ except OSError:
152
+ pass
153
+ try:
154
+ return importlib.metadata.version("bensz-skill-kernel")
155
+ except importlib.metadata.PackageNotFoundError:
156
+ return "0.0.0"
157
+
158
+
159
+ __version__ = _distribution_version()
@@ -0,0 +1,93 @@
1
+ """Implementations for the small, domain-neutral atomic verifier packs.
2
+
3
+ This module lives beside the directory contracts so reviewers can inspect the
4
+ rules independently from the registry and runner plumbing. Each directory's
5
+ ``scripts/verify.py`` is a thin JSON-stdio adapter around ``run_atomic``.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import json
11
+ import re
12
+ from pathlib import Path
13
+ from typing import Any, Mapping
14
+
15
+ from bensz_skill_kernel.runtime import ALLOWED_TRANSITIONS, EventLog
16
+
17
+
18
+ def _parts(request: Any) -> tuple[Mapping[str, Any], Mapping[str, Any]]:
19
+ if hasattr(request, "subject"):
20
+ return request.subject, request.context
21
+ return request.get("subject") or {}, request.get("context") or {}
22
+
23
+
24
+ def _evidence_map(request: Any, evidence: Mapping[str, Any] | None) -> Mapping[str, Any]:
25
+ if evidence:
26
+ return evidence
27
+ if hasattr(request, "evidence"):
28
+ return {item.ref: item for item in request.evidence}
29
+ raw = request.get("evidence") or []
30
+ return {str(item.get("ref", index)): item for index, item in enumerate(raw) if isinstance(item, Mapping)}
31
+
32
+
33
+ def run_atomic(name: str, request: Any, evidence: Mapping[str, Any] | None = None) -> Mapping[str, Any]:
34
+ subject, context = _parts(request)
35
+ evidence = _evidence_map(request, evidence)
36
+ if name == "contract-conformance":
37
+ required = tuple(context.get("required_fields", ()))
38
+ missing = [field for field in required if field not in subject]
39
+ return _result(not missing, {"required_fields": list(required), "missing": missing}, "missing-field", missing)
40
+ if name == "path-scope":
41
+ raw_paths = subject.get("paths") or ([subject["path"]] if subject.get("path") else [])
42
+ allowed = [Path(item).expanduser().resolve() for item in context.get("allowed_paths", ())]
43
+ violations = []
44
+ for raw in raw_paths:
45
+ target = Path(raw).expanduser().resolve()
46
+ # Scope is lexical after ``resolve()`` and must not depend on an
47
+ # allowed directory already existing. Requiring ``is_dir()``
48
+ # made valid output paths fail before their parent was created.
49
+ if not any(target == root or root in target.parents for root in allowed):
50
+ violations.append(str(target))
51
+ return _result(not violations, {"paths": list(raw_paths), "violations": violations}, "path-out-of-scope", violations)
52
+ if name == "schema-conformance":
53
+ data = subject.get("data", subject)
54
+ schema = context.get("schema", {})
55
+ required = schema.get("required", ()) if isinstance(schema, Mapping) else ()
56
+ missing = [key for key in required if not isinstance(data, Mapping) or key not in data]
57
+ return _result(not missing, {"missing": missing}, "schema-required-field", missing)
58
+ if name == "diff-scope":
59
+ changed = set(subject.get("changed_paths", ()))
60
+ violations = sorted(changed - set(context.get("allowed_paths", ())))
61
+ return _result(not violations, {"changed": sorted(changed), "violations": violations}, "unexpected-change", violations)
62
+ if name == "secret-redaction":
63
+ raw = json.dumps(subject, ensure_ascii=False, default=str)
64
+ patterns = (r"[\"']?(?:api[_-]?key|token|password|cookie)[\"']?\s*[:=]\s*[\"']?[^,\s}\"']+", r"sk-[A-Za-z0-9_-]{8,}")
65
+ matches = [pattern for pattern in patterns if re.search(pattern, raw, re.IGNORECASE)]
66
+ return {"verdict": "fail" if matches else "pass", "facts": {"matched_patterns": len(matches)}, "findings": [{"id": "secret-detected", "verdict": "fail"}] if matches else []}
67
+ if name == "evidence-provenance":
68
+ def value(item: Any, key: str) -> Any:
69
+ return item.get(key) if isinstance(item, Mapping) else getattr(item, key, None)
70
+ invalid = [ref for ref, item in evidence.items() if not value(item, "source_type") or not value(item, "content_hash") or not value(item, "collected_at")]
71
+ return _result(not invalid, {"evidence_count": len(evidence)}, "missing-provenance", invalid)
72
+ if name == "event-integrity":
73
+ path = subject.get("path")
74
+ if not path:
75
+ return _result(False, {}, "missing-events-path", ["events"])
76
+ try:
77
+ count = len(EventLog(path).read())
78
+ except Exception as exc:
79
+ return {"verdict": "fail", "uncertainty_reason": str(exc), "findings": [{"id": "event-integrity", "verdict": "fail"}]}
80
+ return {"verdict": "pass", "facts": {"event_count": count}, "findings": []}
81
+ if name == "state-transition":
82
+ current, target = subject.get("current_state"), subject.get("target_state")
83
+ allowed = target in ALLOWED_TRANSITIONS.get(current, ())
84
+ return _result(allowed, {"current_state": current, "target_state": target}, "illegal-transition", [target] if not allowed else [])
85
+ if name == "task-completeness":
86
+ required = tuple(context.get("required_fields", ("artifacts", "verifications", "delivery_report")))
87
+ missing = [key for key in required if not subject.get(key)]
88
+ return _result(not missing, {"missing": missing}, "task-incomplete", missing)
89
+ raise ValueError(f"unknown atomic verifier: {name}")
90
+
91
+
92
+ def _result(ok: bool, facts: Mapping[str, Any], finding_id: str, values: list[Any]) -> Mapping[str, Any]:
93
+ return {"verdict": "pass" if ok else "fail", "facts": dict(facts), "findings": [{"id": finding_id, "value": value, "verdict": "fail"} for value in values]}
@@ -0,0 +1,114 @@
1
+ """Small, dependency-free verifier packs shipped with the kernel.
2
+
3
+ Skills select these by stable id and tags. Domain-specific packs can still be
4
+ registered by a Skill, but common packs live here so Skills do not duplicate
5
+ command, result, or Gate plumbing.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from functools import lru_cache
11
+ from importlib.util import module_from_spec, spec_from_file_location
12
+ from pathlib import Path
13
+ from typing import Any, Mapping
14
+
15
+ from .verifiers import Evidence, PackRegistry, VerifierPack, VerifierSpec
16
+
17
+
18
+ @lru_cache(maxsize=1)
19
+ def _markdown_collector_module():
20
+ """Load the legacy Markdown API without keeping its implementation here."""
21
+ collector_path = (
22
+ Path(__file__).resolve().parent
23
+ / 'verifiers'
24
+ / 'markdown-link-integrity'
25
+ / 'scripts'
26
+ / 'collector.py'
27
+ )
28
+ spec = spec_from_file_location('bensz_skill_kernel._markdown_link_integrity_collector', collector_path)
29
+ if spec is None or spec.loader is None:
30
+ raise ImportError(f'cannot load Markdown collector: {collector_path}')
31
+ module = module_from_spec(spec)
32
+ spec.loader.exec_module(module)
33
+ return module
34
+
35
+
36
+ def collect_markdown(*args: Any, **kwargs: Any) -> dict[str, Any]:
37
+ """Backward-compatible proxy to the Markdown Verifier collector.
38
+
39
+ New code should invoke ``markdown-link-integrity`` through the filesystem
40
+ Verifier entrypoint instead of importing this compatibility API.
41
+ """
42
+ return _markdown_collector_module().collect_markdown(*args, **kwargs)
43
+
44
+
45
+ @lru_cache(maxsize=1)
46
+ def _atomic_module():
47
+ atomic_path = Path(__file__).resolve().parent / 'atomic_verifiers.py'
48
+ spec = spec_from_file_location('bensz_skill_kernel._atomic_verifiers', atomic_path)
49
+ if spec is None or spec.loader is None:
50
+ raise ImportError(f'cannot load atomic verifier rules: {atomic_path}')
51
+ module = module_from_spec(spec)
52
+ spec.loader.exec_module(module)
53
+ return module
54
+
55
+
56
+ CITATION_TRUTH_FIT_SPEC = VerifierSpec(
57
+ verifier_id='bensz.evidence.citation-truth-fit',
58
+ version='1.0.0',
59
+ mode='hybrid',
60
+ capabilities=('evidence.identity', 'semantic.entailment', 'semantic.appropriateness'),
61
+ evidence_requirements=('subject_context', 'source_metadata', 'source_excerpt'),
62
+ uncertainty_policy={'missing_evidence': 'manual_review', 'engine_unavailable': 'unchecked'},
63
+ tags=('common', 'citation', 'semantic', 'evidence'),
64
+ aliases=('citation.truth-and-fit',),
65
+ metadata={'side_effects': 'none', 'requires_external_engine': True},
66
+ )
67
+
68
+
69
+ def _citation_engine_gap(request: Any, evidence: Mapping[str, Evidence]) -> Mapping[str, Any]:
70
+ return {
71
+ 'execution_status': 'unchecked',
72
+ 'verdict': 'unchecked',
73
+ 'uncertainty_reason': 'semantic citation engine is not bundled with the kernel',
74
+ 'evidence_refs': ['subject_context', 'source_metadata', 'source_excerpt'],
75
+ 'model_or_engine': 'none',
76
+ }
77
+
78
+
79
+ def _file_exists(request: Any, evidence: Mapping[str, Evidence]) -> Mapping[str, Any]:
80
+ path = request.subject.get('path')
81
+ exists = bool(path and Path(path).is_file())
82
+ return {'verdict': 'pass' if exists else 'fail', 'facts': {'path': path, 'exists': exists}, 'findings': [] if exists else [{'id': 'missing-file', 'severity': 'required', 'verdict': 'fail', 'message': f'file does not exist: {path}'}]}
83
+
84
+
85
+ FILE_SPEC = VerifierSpec(
86
+ verifier_id='bensz.artifact.file-existence',
87
+ version='1.0.0',
88
+ mode='rule',
89
+ capabilities=('filesystem.read',),
90
+ tags=('common', 'filesystem', 'deterministic'),
91
+ aliases=('artifact.file-exists',),
92
+ metadata={'side_effects': 'none'},
93
+ )
94
+
95
+
96
+ def build_builtin_registry() -> PackRegistry:
97
+ registry = PackRegistry()
98
+ registry.register(VerifierPack(FILE_SPEC, rules=(('file-exists', _file_exists),)))
99
+ registry.register(VerifierPack(CITATION_TRUTH_FIT_SPEC, prompts=(('citation-semantics', _citation_engine_gap),)))
100
+ atomic = (
101
+ ("bensz.contract.conformance", "contract-conformance", "contract"),
102
+ ("bensz.artifact.path-scope", "path-scope", "artifact"),
103
+ ("bensz.artifact.schema-conformance", "schema-conformance", "artifact"),
104
+ ("bensz.source.diff-scope", "diff-scope", "source"),
105
+ ("bensz.security.secret-redaction", "secret-redaction", "security"),
106
+ ("bensz.evidence.provenance", "evidence-provenance", "evidence"),
107
+ ("bensz.runtime.event-integrity", "event-integrity", "runtime"),
108
+ ("bensz.runtime.state-transition", "state-transition", "runtime"),
109
+ ("bensz.runtime.task-completeness", "task-completeness", "runtime"),
110
+ )
111
+ for verifier_id, rule_name, tag in atomic:
112
+ rule = lambda request, evidence, name=rule_name: _atomic_module().run_atomic(name, request, evidence)
113
+ registry.register(VerifierPack(VerifierSpec(verifier_id, "1.0.0", "rule", tags=("common", tag, "deterministic")), rules=((rule_name, rule),)))
114
+ return registry