sage-harness 0.1.0__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.
- sage_harness-0.1.0/LICENSE +21 -0
- sage_harness-0.1.0/MANIFEST.in +8 -0
- sage_harness-0.1.0/PKG-INFO +221 -0
- sage_harness-0.1.0/README.md +190 -0
- sage_harness-0.1.0/docs/sage_harness/.manifest.json +113 -0
- sage_harness-0.1.0/docs/sage_harness/README.md +43 -0
- sage_harness-0.1.0/docs/sage_harness/hooks/capture-declared-risk.md +43 -0
- sage_harness-0.1.0/docs/sage_harness/hooks/generated-artifact-write-guard.md +39 -0
- sage_harness-0.1.0/docs/sage_harness/hooks/post-tool-logger.md +47 -0
- sage_harness-0.1.0/docs/sage_harness/hooks/pre-implementation-gate.md +60 -0
- sage_harness-0.1.0/docs/sage_harness/hooks/pre-phase4-checklist-gate.md +48 -0
- sage_harness-0.1.0/docs/sage_harness/hooks/stop-compliance-report.md +43 -0
- sage_harness-0.1.0/docs/sage_harness/manifest.example.json +29 -0
- sage_harness-0.1.0/pyproject.toml +55 -0
- sage_harness-0.1.0/sage/__init__.py +7 -0
- sage_harness-0.1.0/sage/__main__.py +6 -0
- sage_harness-0.1.0/sage/_resources.py +47 -0
- sage_harness-0.1.0/sage/asset_paths.py +56 -0
- sage_harness-0.1.0/sage/cli.py +48 -0
- sage_harness-0.1.0/sage/commands/__init__.py +1 -0
- sage_harness-0.1.0/sage/commands/_common.py +36 -0
- sage_harness-0.1.0/sage/commands/absorb.py +162 -0
- sage_harness-0.1.0/sage/commands/change.py +126 -0
- sage_harness-0.1.0/sage/commands/doctor.py +136 -0
- sage_harness-0.1.0/sage/commands/generate.py +530 -0
- sage_harness-0.1.0/sage/commands/install.py +170 -0
- sage_harness-0.1.0/sage/commands/override.py +72 -0
- sage_harness-0.1.0/sage/commands/review.py +121 -0
- sage_harness-0.1.0/sage/commands/validate.py +499 -0
- sage_harness-0.1.0/sage/mcp_common.py +338 -0
- sage_harness-0.1.0/sage/profile_validate.py +79 -0
- sage_harness-0.1.0/sage_harness.egg-info/PKG-INFO +221 -0
- sage_harness-0.1.0/sage_harness.egg-info/SOURCES.txt +129 -0
- sage_harness-0.1.0/sage_harness.egg-info/dependency_links.txt +1 -0
- sage_harness-0.1.0/sage_harness.egg-info/entry_points.txt +2 -0
- sage_harness-0.1.0/sage_harness.egg-info/requires.txt +7 -0
- sage_harness-0.1.0/sage_harness.egg-info/top_level.txt +1 -0
- sage_harness-0.1.0/schema/manifest.schema.json +94 -0
- sage_harness-0.1.0/schema/profile.schema.json +76 -0
- sage_harness-0.1.0/scripts/sage_harness/conformance.py +102 -0
- sage_harness-0.1.0/scripts/sage_harness/extract_agent.py +92 -0
- sage_harness-0.1.0/scripts/sage_harness/extract_config_example.py +56 -0
- sage_harness-0.1.0/scripts/sage_harness/extract_skill.py +80 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/adapters/claude/capture-declared-risk.sh +11 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/adapters/claude/post-tool-logger.sh +11 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/adapters/claude/pre-implementation-gate.sh +11 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/adapters/claude/pre-phase4-checklist-gate.sh +11 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/adapters/claude/stop-compliance-report.sh +12 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/adapters/codex/capture-declared-risk.sh +11 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/adapters/codex/post-tool-logger.sh +11 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/adapters/codex/pre-implementation-gate.sh +11 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/adapters/codex/pre-phase4-checklist-gate.sh +11 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/adapters/codex/stop-compliance-report.sh +12 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/capture_declared_risk_core.py +75 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/generated-artifact-write-guard.sh +93 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/policies/knowledge_capture.py +26 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/policies/output_contract_check.py +40 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/post_tool_logger_core.py +70 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/pre_implementation_gate_core.py +262 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/pre_phase4_checklist_gate_core.py +142 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/runtime/hook_runtime.py +383 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/runtime/io_claude.py +132 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/runtime/io_codex.py +189 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/runtime/override_audit.py +108 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/runtime/run_hook.py +49 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/stop_compliance_report_core.py +117 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/strategies/README.md +19 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/strategies/pre_implementation_gate/claude_grep_first.py +39 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/strategies/pre_implementation_gate/codex_feature_signal.py +46 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/fixtures/mcp_chatforyou/docs/sage_harness/mcps/codegraph.md +12 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/fixtures/mcp_chatforyou/docs/sage_harness/mcps/obsidian.md +13 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/run-all.sh +136 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/run-tests.sh +46 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_absorb.py +171 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_asset_paths.py +81 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_capture_declared_risk.py +124 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_change_router.py +76 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_claims_codec.py +114 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_conformance.py +92 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_contract_version.py +49 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_doctor.py +66 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_extract_driver.py +71 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_gen_mcp.py +380 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_gen_roster.py +109 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_generate.py +181 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_golden_instance_e2e.py +165 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_hook_runtime.py +173 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_install.py +119 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_manifest_util.py +72 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_mcp_shadow_pilot.py +90 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_override_audit.py +105 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_post_tool_logger.py +143 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_pre_implementation_gate.py +295 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_pre_phase4_checklist_gate.py +135 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_profile_validate.py +69 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_resources.py +47 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_reverse_extract_agent.py +158 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_reverse_extract_skill.py +125 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_review.py +123 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_reviewer_resolution.py +88 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_runtime_smoke.py +262 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_stop_compliance_report.py +194 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_validate_conformance.py +112 -0
- sage_harness-0.1.0/scripts/sage_harness/hooks/tests/test_validate_safety.py +90 -0
- sage_harness-0.1.0/scripts/sage_harness/manifest_util.py +114 -0
- sage_harness-0.1.0/scripts/sage_harness/reverse_extract_agent.py +188 -0
- sage_harness-0.1.0/scripts/sage_harness/reverse_extract_common.py +219 -0
- sage_harness-0.1.0/scripts/sage_harness/reverse_extract_skill.py +218 -0
- sage_harness-0.1.0/setup.cfg +4 -0
- sage_harness-0.1.0/setup.py +42 -0
- sage_harness-0.1.0/templates/agent.spec.md +19 -0
- sage_harness-0.1.0/templates/claims.yml +17 -0
- sage_harness-0.1.0/templates/core/agents/convention-checker.md +20 -0
- sage_harness-0.1.0/templates/core/agents/implementer-a.md +21 -0
- sage_harness-0.1.0/templates/core/agents/implementer-b.md +21 -0
- sage_harness-0.1.0/templates/core/agents/leader.md +20 -0
- sage_harness-0.1.0/templates/core/agents/qa.md +20 -0
- sage_harness-0.1.0/templates/core/agents/reviewer.md +21 -0
- sage_harness-0.1.0/templates/core/framework/AGENT_GUIDE.md +110 -0
- sage_harness-0.1.0/templates/core/framework/CLAUDE.md +17 -0
- sage_harness-0.1.0/templates/core/framework/CODEX.md +17 -0
- sage_harness-0.1.0/templates/core/framework/docs/agent/bootstrap-authoring.md +137 -0
- sage_harness-0.1.0/templates/core/framework/docs/agent/output-contract.md +17 -0
- sage_harness-0.1.0/templates/core/framework/docs/agent/pdca-templates.md +285 -0
- sage_harness-0.1.0/templates/core/framework/docs/agent/review-protocol.md +15 -0
- sage_harness-0.1.0/templates/core/framework/docs/agent/risk-classification.md +21 -0
- sage_harness-0.1.0/templates/core/framework/scripts/verify-changes.sh +50 -0
- sage_harness-0.1.0/templates/core/framework/verification-protocol.md +25 -0
- sage_harness-0.1.0/templates/hook.spec.md +21 -0
- sage_harness-0.1.0/templates/project-profile.yaml +142 -0
- sage_harness-0.1.0/templates/skill.spec.md +24 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 SeJonJ
|
|
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.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# sdist 에 번들 리소스 포함 — install 이 대상 프로젝트로 복사하는 자산.
|
|
2
|
+
# (sage CLI 는 sage/_resources.py 로 이 트리들을 해석. editable/sdist 레이아웃에서 동작.)
|
|
3
|
+
recursive-include templates *
|
|
4
|
+
recursive-include schema *.json
|
|
5
|
+
recursive-include scripts/sage_harness *.py *.sh *.md
|
|
6
|
+
recursive-include docs/sage_harness *.md *.json *.yml
|
|
7
|
+
include README.md
|
|
8
|
+
include AGENT_GUIDE.md
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sage-harness
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Governance harness for AI coding agents — spec-SSOT closed loop for Claude Code and Codex
|
|
5
|
+
Author-email: SeJonJ <wkdtpwhs@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/SeJonJ/SAGE
|
|
8
|
+
Project-URL: Repository, https://github.com/SeJonJ/SAGE
|
|
9
|
+
Project-URL: Issues, https://github.com/SeJonJ/SAGE/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/SeJonJ/SAGE/releases
|
|
11
|
+
Keywords: ai,agent,governance,claude,codex,harness,hooks,spec,ssot,llm,automation
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
22
|
+
Classifier: Topic :: Utilities
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: pyyaml>=6.0
|
|
27
|
+
Requires-Dist: tomli>=2.0; python_version < "3.11"
|
|
28
|
+
Provides-Extra: schema
|
|
29
|
+
Requires-Dist: jsonschema>=4.0; extra == "schema"
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+
# SAGE — System for Agentic Governance & Engineering
|
|
33
|
+
|
|
34
|
+
[](https://github.com/SeJonJ/SAGE/actions/workflows/ci.yml)
|
|
35
|
+
[](https://pypi.org/project/sage-harness/)
|
|
36
|
+
[](https://pypi.org/project/sage-harness/)
|
|
37
|
+
[](LICENSE)
|
|
38
|
+
|
|
39
|
+
**AI 코딩 에이전트를 위한 거버넌스 하네스.** 자산마다 spec 파일 하나 — SAGE가 런타임 설정을 생성하고, drift를 검증하고, hook이 실행 시점에 위반을 차단합니다. Claude Code와 Codex 양쪽에서 동작합니다.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 왜 SAGE인가
|
|
44
|
+
|
|
45
|
+
AI 에이전트는 빠르지만 규칙을 조용히 어깁니다:
|
|
46
|
+
|
|
47
|
+
- plan 문서 없이 고위험 파일을 수정한다
|
|
48
|
+
- PDCA 단계를 건너뛴다
|
|
49
|
+
- 생성된 산출물을 손으로 덮어쓴다
|
|
50
|
+
- 자기 코드를 자기 모델로 리뷰한다 (단일 모델 편향)
|
|
51
|
+
|
|
52
|
+
보통은 사람이 매번 잔소리하거나, 프로젝트마다 `.claude/`·`.codex/` 설정을 손으로 관리합니다. SAGE는 그 두 가지를 **spec-SSOT 폐루프**로 대체합니다.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## 빠른 시작 (30초)
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
pip install sage-harness
|
|
60
|
+
|
|
61
|
+
cd your-project
|
|
62
|
+
sage install # 런타임 선택: claude 또는 codex
|
|
63
|
+
# hook·에이전트 spec·AGENT_GUIDE·manifest 자동 배치
|
|
64
|
+
|
|
65
|
+
sage generate # spec md → .claude/.codex 산출물 + manifest 스탬프
|
|
66
|
+
sage validate # drift · staleness · conformance 검사 (읽기 전용)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
끝입니다. 이제 AI 에이전트는 강제력 있는 규칙 위에서 동작합니다.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## 동작 원리
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
사람이 의도를 쓴다 generate 런타임에 배치 validate / hook 게이트
|
|
77
|
+
docs/.../hooks/{id}.md ──────────► .claude/hooks/ ──────────► 위반 시 BLOCK
|
|
78
|
+
docs/.../agents/{id}.md .codex/agents/ drift 시 validate FAIL
|
|
79
|
+
docs/.../mcps/{id}.md .mcp.json │
|
|
80
|
+
▲ manifest 스탬프 │
|
|
81
|
+
└────────────── absorb (직접수정 → spec patch 제안) ─────────────┘
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
핵심은 **폐루프**입니다 — spec에서 산출물을 만들고(generate), 산출물이 spec과 어긋나면 잡아냅니다(validate), 산출물을 직접 수정하면 차단하고(write-guard), 비상 수정분은 다시 spec으로 흡수 제안합니다(absorb).
|
|
85
|
+
|
|
86
|
+
엔진 자체에는 **도메인 값이 0개**입니다 — 스택·위험 경로·PDCA 키워드는 전부 `sage/project-profile.yaml`에서 주입됩니다. 프로필만 바꾸면 같은 엔진이 다른 스택을 거버넌스합니다.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## 자산 종류 4종
|
|
91
|
+
|
|
92
|
+
| kind | 생성 성격 | SSOT | 산출물 |
|
|
93
|
+
|---|---|---|---|
|
|
94
|
+
| `hook` | 결정론 (순수 함수) | `docs/sage_harness/hooks/{id}.md` + `{id}_core.py` | `settings.json` / `hooks.json` + 런타임 shim |
|
|
95
|
+
| `agent` | interpretive (AI 렌더) | `docs/sage_harness/agents/{id}.md` + `{id}.claims.yml` | `.claude/agents/` / `.codex/agents/` |
|
|
96
|
+
| `skill` | interpretive (AI 렌더) | `docs/sage_harness/skills/{id}.md` + `{id}.claims.yml` | `.claude/skills/` / `.codex/skills/` |
|
|
97
|
+
| `mcp` | 결정론 (선언 데이터 직렬화) | `docs/sage_harness/mcps/{id}.md` (frontmatter payload) | `.mcp.json` (claude) · `.codex/config.toml` managed-block (codex) |
|
|
98
|
+
|
|
99
|
+
> **MCP 거버넌스**: 시크릿은 env 변수명만 허용 (`${VAR}` placeholder). 리터럴 시크릿 값이 spec에 있으면 generate 전 FAIL (fail-closed). `.mcp.json`은 SAGE 소유(write-guard), `config.toml`의 비-MCP 설정은 보존합니다.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Hook 6종 (무엇을 강제하나)
|
|
104
|
+
|
|
105
|
+
| hook | 실행 시점 | 역할 |
|
|
106
|
+
|---|---|---|
|
|
107
|
+
| `pre-implementation-gate` | 파일 수정 전 (PreToolUse) | 위험도 L0–L3 분류 · plan 문서 · PDCA phase 강제. 미충족 시 BLOCK |
|
|
108
|
+
| `pre-phase4-checklist-gate` | 단계 전환 전 | PDCA 03→04 전환 시 체크리스트 완료 강제 |
|
|
109
|
+
| `capture-declared-risk` | 프롬프트 제출 (UserPromptSubmit) | 유저가 선언한 작업 위험레벨 포착 |
|
|
110
|
+
| `post-tool-logger` | 도구 실행 후 (PostToolUse) | 변경 분류를 세션 JSONL에 기록 |
|
|
111
|
+
| `stop-compliance-report` | 세션 종료 (Stop) | 컴플라이언스 리포트 생성 |
|
|
112
|
+
| `generated-artifact-write-guard` | 파일 수정 전 (native) | 생성 산출물 직접수정 차단 → spec으로 redirect |
|
|
113
|
+
|
|
114
|
+
Hook은 **순수 코어 + 어댑터** 구조입니다 — 정책 판정(`{id}_core.py`)은 I/O가 없는 순수 함수이고, 런타임별 I/O는 얇은 어댑터가 담당합니다. 같은 정책, 런타임 간 동일한 동작.
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## CLI 참조
|
|
119
|
+
|
|
120
|
+
| 명령 | 역할 |
|
|
121
|
+
|---|---|
|
|
122
|
+
| `sage install` | 런타임 선택 (claude/codex) · CORE 하네스 배치 (hook·에이전트 spec·AGENT_GUIDE·manifest) |
|
|
123
|
+
| `sage generate` | spec md → 등록 산출물 + `{host}/hooks` shim + profile 컴파일 + manifest 스탬프 |
|
|
124
|
+
| `sage generate --kind roster` | `profile.components` → `implementer-<comp>` 에이전트 spec 결정론 scaffold |
|
|
125
|
+
| `sage generate --kind mcp` | `docs/sage_harness/mcps/{id}.md` → `.mcp.json` (claude) / `config.toml` managed-block (codex) |
|
|
126
|
+
| `sage validate` | drift · staleness · conformance · regression 검사. `--check` (빠름) / `--schema` (JSON Schema) |
|
|
127
|
+
| `sage review` | `auto_approve_safe_default` — 통과는 자동승인, 사람은 예외만 검토 |
|
|
128
|
+
| `sage absorb` | 직접수정 diff → spec patch 제안 (자동 반영 없음) |
|
|
129
|
+
| `sage doctor` | 옵션 의존성 점검 · 실행 환경 진단 · cross-model reviewer fallback 노출 |
|
|
130
|
+
| `sage change` | 자연어 의도 → generate/absorb 라우팅 안내 (v1) |
|
|
131
|
+
| `sage override` | 게이트 BLOCK 시한부 합법 우회 + append-only 감사 로그 (`.sage/override.jsonl`) |
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## 프로필 예시
|
|
136
|
+
|
|
137
|
+
```yaml
|
|
138
|
+
# sage/project-profile.yaml — 도메인 값은 전부 여기, 엔진에는 0개
|
|
139
|
+
project: { name: "acme", prefix: "acme" }
|
|
140
|
+
risk:
|
|
141
|
+
l1_path_globs: ["*frontend/*.js"] # 저위험 (UI)
|
|
142
|
+
l2_path_globs: ["*backend/*.java"] # 소스 (build+test+lint 필요)
|
|
143
|
+
l3_filename_globs: ["*payment*", "*auth*"] # 고위험 (plan + 리뷰 필수)
|
|
144
|
+
l3_content_keywords: ["encrypt", "PrivateKey", "chargeCard"]
|
|
145
|
+
plan_glob: "plan_docs/**/*.md"
|
|
146
|
+
components: [backend, frontend] # → sage generate --kind roster
|
|
147
|
+
cross_model:
|
|
148
|
+
enabled: true
|
|
149
|
+
opposite_runtime: codex # phase-05 리뷰를 codex로 실행
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
`cross_model.opposite_runtime: codex` 설정 시, 단일 모델이 놓친 P1 이슈를 codex가 실제로 적발한 사례가 있습니다 (weatherapp Tier 2 검증).
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## 설치
|
|
157
|
+
|
|
158
|
+
**PyPI (권장):**
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
pip install sage-harness
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
**JSON Schema 검증 포함:**
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
pip install "sage-harness[schema]"
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**소스에서 설치 (editable):**
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
git clone https://github.com/SeJonJ/SAGE.git
|
|
174
|
+
cd SAGE
|
|
175
|
+
pip install -e .
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
요구사항: Python 3.10+, bash, git.
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## 새 버전 배포
|
|
183
|
+
|
|
184
|
+
태그를 push하면 [publish workflow](.github/workflows/publish.yml)가 PyPI에 자동 배포합니다:
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
git tag v0.2.0
|
|
188
|
+
git push origin v0.2.0
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
> 선행 조건: PyPI에서 [Trusted Publisher](https://docs.pypi.org/trusted-publishers/) 등록 (Repository: `SeJonJ/SAGE`, Workflow: `publish.yml`, Environment: `release`).
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## 이런 분께 맞습니다
|
|
196
|
+
|
|
197
|
+
**아래에 해당하면 SAGE가 맞습니다:**
|
|
198
|
+
|
|
199
|
+
- Claude Code 또는 Codex로 실무 작업 중이고, 에이전트가 규칙을 지키도록 강제하고 싶다
|
|
200
|
+
- 프로젝트마다 `.claude/`·`.codex/` 설정을 손으로 다시 쓰는 게 지쳤다
|
|
201
|
+
- Claude + Codex 교차 리뷰(cross-model review) 구조를 갖추고 싶다
|
|
202
|
+
- CI에서 검증 가능한 spec 기반 하네스가 필요하다
|
|
203
|
+
|
|
204
|
+
**아래에 해당하면 맞지 않습니다:**
|
|
205
|
+
|
|
206
|
+
- 간단한 프롬프트 팁이 필요한 경우 — SAGE는 프레임워크이지 스니펫이 아닙니다
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## 검증 이력
|
|
211
|
+
|
|
212
|
+
- **외부검토 1차 하드닝 11항목** 완료
|
|
213
|
+
- **Weatherapp Tier 2** 골든 인스턴스: `install → 대화형 부트스트랩 → generate → validate → PDCA phases → cross-model review → 수정 → report` 전체 파이프라인 실세계 실증
|
|
214
|
+
- **MCP kind**: codex 6라운드 cross-model 리뷰, P0×3 + P1×8 + P2×2 전부 해소, 엔진 도메인 토큰 0
|
|
215
|
+
- **CI** wheel smoke test 강제 (clean venv wheel-only 설치 → generate → validate PASS)
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## 라이선스
|
|
220
|
+
|
|
221
|
+
MIT — [LICENSE](LICENSE) 참조.
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# SAGE — System for Agentic Governance & Engineering
|
|
2
|
+
|
|
3
|
+
[](https://github.com/SeJonJ/SAGE/actions/workflows/ci.yml)
|
|
4
|
+
[](https://pypi.org/project/sage-harness/)
|
|
5
|
+
[](https://pypi.org/project/sage-harness/)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
**AI 코딩 에이전트를 위한 거버넌스 하네스.** 자산마다 spec 파일 하나 — SAGE가 런타임 설정을 생성하고, drift를 검증하고, hook이 실행 시점에 위반을 차단합니다. Claude Code와 Codex 양쪽에서 동작합니다.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 왜 SAGE인가
|
|
13
|
+
|
|
14
|
+
AI 에이전트는 빠르지만 규칙을 조용히 어깁니다:
|
|
15
|
+
|
|
16
|
+
- plan 문서 없이 고위험 파일을 수정한다
|
|
17
|
+
- PDCA 단계를 건너뛴다
|
|
18
|
+
- 생성된 산출물을 손으로 덮어쓴다
|
|
19
|
+
- 자기 코드를 자기 모델로 리뷰한다 (단일 모델 편향)
|
|
20
|
+
|
|
21
|
+
보통은 사람이 매번 잔소리하거나, 프로젝트마다 `.claude/`·`.codex/` 설정을 손으로 관리합니다. SAGE는 그 두 가지를 **spec-SSOT 폐루프**로 대체합니다.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 빠른 시작 (30초)
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pip install sage-harness
|
|
29
|
+
|
|
30
|
+
cd your-project
|
|
31
|
+
sage install # 런타임 선택: claude 또는 codex
|
|
32
|
+
# hook·에이전트 spec·AGENT_GUIDE·manifest 자동 배치
|
|
33
|
+
|
|
34
|
+
sage generate # spec md → .claude/.codex 산출물 + manifest 스탬프
|
|
35
|
+
sage validate # drift · staleness · conformance 검사 (읽기 전용)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
끝입니다. 이제 AI 에이전트는 강제력 있는 규칙 위에서 동작합니다.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## 동작 원리
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
사람이 의도를 쓴다 generate 런타임에 배치 validate / hook 게이트
|
|
46
|
+
docs/.../hooks/{id}.md ──────────► .claude/hooks/ ──────────► 위반 시 BLOCK
|
|
47
|
+
docs/.../agents/{id}.md .codex/agents/ drift 시 validate FAIL
|
|
48
|
+
docs/.../mcps/{id}.md .mcp.json │
|
|
49
|
+
▲ manifest 스탬프 │
|
|
50
|
+
└────────────── absorb (직접수정 → spec patch 제안) ─────────────┘
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
핵심은 **폐루프**입니다 — spec에서 산출물을 만들고(generate), 산출물이 spec과 어긋나면 잡아냅니다(validate), 산출물을 직접 수정하면 차단하고(write-guard), 비상 수정분은 다시 spec으로 흡수 제안합니다(absorb).
|
|
54
|
+
|
|
55
|
+
엔진 자체에는 **도메인 값이 0개**입니다 — 스택·위험 경로·PDCA 키워드는 전부 `sage/project-profile.yaml`에서 주입됩니다. 프로필만 바꾸면 같은 엔진이 다른 스택을 거버넌스합니다.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## 자산 종류 4종
|
|
60
|
+
|
|
61
|
+
| kind | 생성 성격 | SSOT | 산출물 |
|
|
62
|
+
|---|---|---|---|
|
|
63
|
+
| `hook` | 결정론 (순수 함수) | `docs/sage_harness/hooks/{id}.md` + `{id}_core.py` | `settings.json` / `hooks.json` + 런타임 shim |
|
|
64
|
+
| `agent` | interpretive (AI 렌더) | `docs/sage_harness/agents/{id}.md` + `{id}.claims.yml` | `.claude/agents/` / `.codex/agents/` |
|
|
65
|
+
| `skill` | interpretive (AI 렌더) | `docs/sage_harness/skills/{id}.md` + `{id}.claims.yml` | `.claude/skills/` / `.codex/skills/` |
|
|
66
|
+
| `mcp` | 결정론 (선언 데이터 직렬화) | `docs/sage_harness/mcps/{id}.md` (frontmatter payload) | `.mcp.json` (claude) · `.codex/config.toml` managed-block (codex) |
|
|
67
|
+
|
|
68
|
+
> **MCP 거버넌스**: 시크릿은 env 변수명만 허용 (`${VAR}` placeholder). 리터럴 시크릿 값이 spec에 있으면 generate 전 FAIL (fail-closed). `.mcp.json`은 SAGE 소유(write-guard), `config.toml`의 비-MCP 설정은 보존합니다.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Hook 6종 (무엇을 강제하나)
|
|
73
|
+
|
|
74
|
+
| hook | 실행 시점 | 역할 |
|
|
75
|
+
|---|---|---|
|
|
76
|
+
| `pre-implementation-gate` | 파일 수정 전 (PreToolUse) | 위험도 L0–L3 분류 · plan 문서 · PDCA phase 강제. 미충족 시 BLOCK |
|
|
77
|
+
| `pre-phase4-checklist-gate` | 단계 전환 전 | PDCA 03→04 전환 시 체크리스트 완료 강제 |
|
|
78
|
+
| `capture-declared-risk` | 프롬프트 제출 (UserPromptSubmit) | 유저가 선언한 작업 위험레벨 포착 |
|
|
79
|
+
| `post-tool-logger` | 도구 실행 후 (PostToolUse) | 변경 분류를 세션 JSONL에 기록 |
|
|
80
|
+
| `stop-compliance-report` | 세션 종료 (Stop) | 컴플라이언스 리포트 생성 |
|
|
81
|
+
| `generated-artifact-write-guard` | 파일 수정 전 (native) | 생성 산출물 직접수정 차단 → spec으로 redirect |
|
|
82
|
+
|
|
83
|
+
Hook은 **순수 코어 + 어댑터** 구조입니다 — 정책 판정(`{id}_core.py`)은 I/O가 없는 순수 함수이고, 런타임별 I/O는 얇은 어댑터가 담당합니다. 같은 정책, 런타임 간 동일한 동작.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## CLI 참조
|
|
88
|
+
|
|
89
|
+
| 명령 | 역할 |
|
|
90
|
+
|---|---|
|
|
91
|
+
| `sage install` | 런타임 선택 (claude/codex) · CORE 하네스 배치 (hook·에이전트 spec·AGENT_GUIDE·manifest) |
|
|
92
|
+
| `sage generate` | spec md → 등록 산출물 + `{host}/hooks` shim + profile 컴파일 + manifest 스탬프 |
|
|
93
|
+
| `sage generate --kind roster` | `profile.components` → `implementer-<comp>` 에이전트 spec 결정론 scaffold |
|
|
94
|
+
| `sage generate --kind mcp` | `docs/sage_harness/mcps/{id}.md` → `.mcp.json` (claude) / `config.toml` managed-block (codex) |
|
|
95
|
+
| `sage validate` | drift · staleness · conformance · regression 검사. `--check` (빠름) / `--schema` (JSON Schema) |
|
|
96
|
+
| `sage review` | `auto_approve_safe_default` — 통과는 자동승인, 사람은 예외만 검토 |
|
|
97
|
+
| `sage absorb` | 직접수정 diff → spec patch 제안 (자동 반영 없음) |
|
|
98
|
+
| `sage doctor` | 옵션 의존성 점검 · 실행 환경 진단 · cross-model reviewer fallback 노출 |
|
|
99
|
+
| `sage change` | 자연어 의도 → generate/absorb 라우팅 안내 (v1) |
|
|
100
|
+
| `sage override` | 게이트 BLOCK 시한부 합법 우회 + append-only 감사 로그 (`.sage/override.jsonl`) |
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## 프로필 예시
|
|
105
|
+
|
|
106
|
+
```yaml
|
|
107
|
+
# sage/project-profile.yaml — 도메인 값은 전부 여기, 엔진에는 0개
|
|
108
|
+
project: { name: "acme", prefix: "acme" }
|
|
109
|
+
risk:
|
|
110
|
+
l1_path_globs: ["*frontend/*.js"] # 저위험 (UI)
|
|
111
|
+
l2_path_globs: ["*backend/*.java"] # 소스 (build+test+lint 필요)
|
|
112
|
+
l3_filename_globs: ["*payment*", "*auth*"] # 고위험 (plan + 리뷰 필수)
|
|
113
|
+
l3_content_keywords: ["encrypt", "PrivateKey", "chargeCard"]
|
|
114
|
+
plan_glob: "plan_docs/**/*.md"
|
|
115
|
+
components: [backend, frontend] # → sage generate --kind roster
|
|
116
|
+
cross_model:
|
|
117
|
+
enabled: true
|
|
118
|
+
opposite_runtime: codex # phase-05 리뷰를 codex로 실행
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
`cross_model.opposite_runtime: codex` 설정 시, 단일 모델이 놓친 P1 이슈를 codex가 실제로 적발한 사례가 있습니다 (weatherapp Tier 2 검증).
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## 설치
|
|
126
|
+
|
|
127
|
+
**PyPI (권장):**
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
pip install sage-harness
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**JSON Schema 검증 포함:**
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
pip install "sage-harness[schema]"
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**소스에서 설치 (editable):**
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
git clone https://github.com/SeJonJ/SAGE.git
|
|
143
|
+
cd SAGE
|
|
144
|
+
pip install -e .
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
요구사항: Python 3.10+, bash, git.
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## 새 버전 배포
|
|
152
|
+
|
|
153
|
+
태그를 push하면 [publish workflow](.github/workflows/publish.yml)가 PyPI에 자동 배포합니다:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
git tag v0.2.0
|
|
157
|
+
git push origin v0.2.0
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
> 선행 조건: PyPI에서 [Trusted Publisher](https://docs.pypi.org/trusted-publishers/) 등록 (Repository: `SeJonJ/SAGE`, Workflow: `publish.yml`, Environment: `release`).
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## 이런 분께 맞습니다
|
|
165
|
+
|
|
166
|
+
**아래에 해당하면 SAGE가 맞습니다:**
|
|
167
|
+
|
|
168
|
+
- Claude Code 또는 Codex로 실무 작업 중이고, 에이전트가 규칙을 지키도록 강제하고 싶다
|
|
169
|
+
- 프로젝트마다 `.claude/`·`.codex/` 설정을 손으로 다시 쓰는 게 지쳤다
|
|
170
|
+
- Claude + Codex 교차 리뷰(cross-model review) 구조를 갖추고 싶다
|
|
171
|
+
- CI에서 검증 가능한 spec 기반 하네스가 필요하다
|
|
172
|
+
|
|
173
|
+
**아래에 해당하면 맞지 않습니다:**
|
|
174
|
+
|
|
175
|
+
- 간단한 프롬프트 팁이 필요한 경우 — SAGE는 프레임워크이지 스니펫이 아닙니다
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## 검증 이력
|
|
180
|
+
|
|
181
|
+
- **외부검토 1차 하드닝 11항목** 완료
|
|
182
|
+
- **Weatherapp Tier 2** 골든 인스턴스: `install → 대화형 부트스트랩 → generate → validate → PDCA phases → cross-model review → 수정 → report` 전체 파이프라인 실세계 실증
|
|
183
|
+
- **MCP kind**: codex 6라운드 cross-model 리뷰, P0×3 + P1×8 + P2×2 전부 해소, 엔진 도메인 토큰 0
|
|
184
|
+
- **CI** wheel smoke test 강제 (clean venv wheel-only 설치 → generate → validate PASS)
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## 라이선스
|
|
189
|
+
|
|
190
|
+
MIT — [LICENSE](LICENSE) 참조.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
{
|
|
2
|
+
"sage_version": "0.1.0",
|
|
3
|
+
"generator_version": "0.1.0",
|
|
4
|
+
"template_version": "0.1.0",
|
|
5
|
+
"host_runtime": "claude",
|
|
6
|
+
"assets": {
|
|
7
|
+
"hooks/capture-declared-risk": {
|
|
8
|
+
"spec_hash": "sha256:b0d38a4480d7cacf863b40a0e8753707a6935db154440118a70aa5b4adb8b9e9",
|
|
9
|
+
"canonical_hash": "sha256:eaf95e8df3c5521a3b1f3eabd735a8e8937573090a6a60e8ac0c0f80dfba9e7a",
|
|
10
|
+
"adapter_hash": {
|
|
11
|
+
"claude": "sha256:dd4155c7a38974f513d9fdadeccbe9b914e9a2dd40ab5b6002dc976699be4b56",
|
|
12
|
+
"codex": "sha256:dfd1c978994ea5bd6da91b39ae7940d8daebb69b81123ebf19d153f668249687"
|
|
13
|
+
},
|
|
14
|
+
"adapter_contract_version": "1",
|
|
15
|
+
"render_hash": {
|
|
16
|
+
"claude": "sha256:dd4155c7a38974f513d9fdadeccbe9b914e9a2dd40ab5b6002dc976699be4b56",
|
|
17
|
+
"codex": "sha256:dfd1c978994ea5bd6da91b39ae7940d8daebb69b81123ebf19d153f668249687"
|
|
18
|
+
},
|
|
19
|
+
"conformance": "PASS",
|
|
20
|
+
"risk": [],
|
|
21
|
+
"unresolved": [],
|
|
22
|
+
"form": "core_adapter",
|
|
23
|
+
"test": "scripts/sage_harness/hooks/tests/test_capture_declared_risk.py"
|
|
24
|
+
},
|
|
25
|
+
"hooks/post-tool-logger": {
|
|
26
|
+
"spec_hash": "sha256:9bcc616cb18a6dc4ad91646e1fdff815d2958822a8cd38b58d368a430367a718",
|
|
27
|
+
"canonical_hash": "sha256:69e89672b17bbaf723bb9633518fc4ca8fdae4b376499c21edfe400d642f7f48",
|
|
28
|
+
"adapter_hash": {
|
|
29
|
+
"claude": "sha256:c843bd1070c9de59b01123c1de72332e77e265f9107051f9e094012f40b085e1",
|
|
30
|
+
"codex": "sha256:b37349688572c5e6925b32689517e3ecd4c714b2b59dba890f1ffb980adb1ed9"
|
|
31
|
+
},
|
|
32
|
+
"adapter_contract_version": "1",
|
|
33
|
+
"render_hash": {
|
|
34
|
+
"claude": "sha256:c843bd1070c9de59b01123c1de72332e77e265f9107051f9e094012f40b085e1",
|
|
35
|
+
"codex": "sha256:b37349688572c5e6925b32689517e3ecd4c714b2b59dba890f1ffb980adb1ed9"
|
|
36
|
+
},
|
|
37
|
+
"conformance": "PASS",
|
|
38
|
+
"risk": [],
|
|
39
|
+
"unresolved": [],
|
|
40
|
+
"form": "core_adapter",
|
|
41
|
+
"test": "scripts/sage_harness/hooks/tests/test_post_tool_logger.py"
|
|
42
|
+
},
|
|
43
|
+
"hooks/pre-phase4-checklist-gate": {
|
|
44
|
+
"spec_hash": "sha256:9d1f8a28c5cd2b44158b7bf64b8addfc2fcdb5f9152ae225d5e41978c2dabf9d",
|
|
45
|
+
"canonical_hash": "sha256:fcaa8ffa11c08e0f63cdd57853c34fe71fe3a09a4ef953dcc4165423116ddf89",
|
|
46
|
+
"adapter_hash": {
|
|
47
|
+
"claude": "sha256:9b02157df8b4e4db0ce4e96edabc68601f781bccba802ca7b2f81c1f85d7955c",
|
|
48
|
+
"codex": "sha256:90a0205df56a47207e6e610a4a7f32dea87b2a42d893eef4ec59529f65e1747a"
|
|
49
|
+
},
|
|
50
|
+
"adapter_contract_version": "1",
|
|
51
|
+
"render_hash": {
|
|
52
|
+
"claude": "sha256:9b02157df8b4e4db0ce4e96edabc68601f781bccba802ca7b2f81c1f85d7955c",
|
|
53
|
+
"codex": "sha256:90a0205df56a47207e6e610a4a7f32dea87b2a42d893eef4ec59529f65e1747a"
|
|
54
|
+
},
|
|
55
|
+
"conformance": "PASS",
|
|
56
|
+
"risk": [],
|
|
57
|
+
"unresolved": [],
|
|
58
|
+
"form": "core_adapter",
|
|
59
|
+
"test": "scripts/sage_harness/hooks/tests/test_pre_phase4_checklist_gate.py"
|
|
60
|
+
},
|
|
61
|
+
"hooks/pre-implementation-gate": {
|
|
62
|
+
"spec_hash": "sha256:1169b547b3ac05599c159b1b68f37dafa1cc23d568f40adc1ccae628f4176394",
|
|
63
|
+
"canonical_hash": "sha256:8dbbd5a8614ebe1b6abb3b768d2723ca158926a451870f51a0f8f488e3b8e4b7",
|
|
64
|
+
"adapter_hash": {
|
|
65
|
+
"claude": "sha256:54e765c0dad01e4c5bce287e95c29564eb4d77995dbafa7681413090f7574486",
|
|
66
|
+
"codex": "sha256:c0fd9948b1af347c797bcd460671c7a33b8a98d7cc6d8b3464773a4acf031ded"
|
|
67
|
+
},
|
|
68
|
+
"adapter_contract_version": "1",
|
|
69
|
+
"render_hash": {
|
|
70
|
+
"claude": "sha256:54e765c0dad01e4c5bce287e95c29564eb4d77995dbafa7681413090f7574486",
|
|
71
|
+
"codex": "sha256:c0fd9948b1af347c797bcd460671c7a33b8a98d7cc6d8b3464773a4acf031ded"
|
|
72
|
+
},
|
|
73
|
+
"conformance": "PASS",
|
|
74
|
+
"safety_degraded": false,
|
|
75
|
+
"risk": [],
|
|
76
|
+
"unresolved": [],
|
|
77
|
+
"form": "core_adapter",
|
|
78
|
+
"test": "scripts/sage_harness/hooks/tests/test_pre_implementation_gate.py",
|
|
79
|
+
"l3_review_strategy": "codex_feature_signal"
|
|
80
|
+
},
|
|
81
|
+
"hooks/stop-compliance-report": {
|
|
82
|
+
"spec_hash": "sha256:04cdde06cee3563754dc9cdb7e45cf3c01ca05b161885dec0c42155d5001c898",
|
|
83
|
+
"canonical_hash": "sha256:9722b3c9694ea0649208fb0ae021467cd872ded6b4328794aa8b08dc5690fcb6",
|
|
84
|
+
"adapter_hash": {
|
|
85
|
+
"claude": "sha256:031dcf4cee2de44cd3f5af5e4e38e95aa511704cfaa55b29f84d5d0b2bc7f8d0",
|
|
86
|
+
"codex": "sha256:1e3437fb58f182aa65a1c36669f008db6c61d9ca92a3b9b6c8d1cb0e4d4e79b1"
|
|
87
|
+
},
|
|
88
|
+
"adapter_contract_version": "1",
|
|
89
|
+
"render_hash": {
|
|
90
|
+
"claude": "sha256:031dcf4cee2de44cd3f5af5e4e38e95aa511704cfaa55b29f84d5d0b2bc7f8d0",
|
|
91
|
+
"codex": "sha256:1e3437fb58f182aa65a1c36669f008db6c61d9ca92a3b9b6c8d1cb0e4d4e79b1"
|
|
92
|
+
},
|
|
93
|
+
"conformance": "PASS",
|
|
94
|
+
"risk": [],
|
|
95
|
+
"unresolved": [],
|
|
96
|
+
"form": "core_adapter",
|
|
97
|
+
"test": "scripts/sage_harness/hooks/tests/test_stop_compliance_report.py"
|
|
98
|
+
},
|
|
99
|
+
"hooks/generated-artifact-write-guard": {
|
|
100
|
+
"spec_hash": "sha256:918c8c54d3fa7c5c061d959acde1b3dd1fd390cea8b6e992356070d7d2a25cf6",
|
|
101
|
+
"canonical_hash": "sha256:1ebcce5a698ee64bced65849aa865cdb0d9cf3c43772481bd095d9a37f403628",
|
|
102
|
+
"render_hash": {
|
|
103
|
+
"native": "sha256:1ebcce5a698ee64bced65849aa865cdb0d9cf3c43772481bd095d9a37f403628"
|
|
104
|
+
},
|
|
105
|
+
"adapter_contract_version": "1",
|
|
106
|
+
"conformance": "PASS",
|
|
107
|
+
"form": "native",
|
|
108
|
+
"test": "scripts/sage_harness/hooks/tests/run-tests.sh",
|
|
109
|
+
"risk": [],
|
|
110
|
+
"unresolved": []
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# docs/sage_harness — 자산 intent SSOT
|
|
2
|
+
|
|
3
|
+
SAGE 자산(hook/agent/skill)의 **의도(intent) 단일 진실원**. `.claude/.codex` 산출물은 여기서
|
|
4
|
+
생성되는 generated artifact이며 **직접수정 금지(write guard로 block)**.
|
|
5
|
+
|
|
6
|
+
> [!important] 프레임워크 ↔ 인스턴스 경계 (제약 #2: SAGE 독립)
|
|
7
|
+
> **이 레포는 프레임워크(엔진 + CORE)만 담는다 — 특정 소비 프로젝트 인스턴스는 두지 않는다.**
|
|
8
|
+
> 그래서 `agents/`·`skills/` 는 프레임워크 레포에선 비어 있고(`.gitkeep`), `hooks/` 만 CORE 6종 spec 을 담는다.
|
|
9
|
+
> - **프레임워크(재사용)**: `sage/` CLI, `scripts/sage_harness/*.py`(엔진: reverse_extract_agent, conformance),
|
|
10
|
+
> hook `*_core.py` + adapters(정본) + `strategies/**`·`policies/**`, `schema/`, `templates/`(CORE 중립 roster/framework/hook spec).
|
|
11
|
+
> 엔진은 도메인값 0(검증: config 없으면 owned_paths 0 / 설치 트리 스택 토큰 0).
|
|
12
|
+
> - **인스턴스(소비 프로젝트)**: `sage install` 로 CORE 를 받은 뒤 자기 `project-profile.yaml` + `ExtractConfig` 로
|
|
13
|
+
> agents/skills/claims 를 채운다. 인스턴스 자산은 **소비 프로젝트 레포에** 산다(이 프레임워크 레포엔 없음).
|
|
14
|
+
> - **예시**: 실제 매핑 worked example 은 루트 `README.md` 참조. 테스트/문서용 generic 예시는
|
|
15
|
+
> `scripts/sage_harness/extract_config_example.py` + `fixtures/**/example.profile.json`.
|
|
16
|
+
> - **브랜드/접두**: `project.prefix`(기본 `sage`) — `sage install --prefix <brand>` 로 설정.
|
|
17
|
+
|
|
18
|
+
## 레이아웃
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
docs/sage_harness/
|
|
22
|
+
├── .manifest.json # spec_hash / render_hash(target별) / claims_hash / conformance 추적
|
|
23
|
+
├── hooks/{id}.md # hook 정책·등록·테스트 명세 (알고리즘: core_adapter={id}_core.py / native={id}.sh)
|
|
24
|
+
├── agents/{id}.md # agent intent + advisory_scope (사람 수기 최소 단위)
|
|
25
|
+
├── agents/{id}.claims.yml # 자동도출 claims (reverse_extract 생성 — 사람 intent와 분리)
|
|
26
|
+
└── skills/{id}.md # skill intent + when_to_use + procedure
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 원칙 (최종검증 노트)
|
|
30
|
+
|
|
31
|
+
- 사람 수기 최소 = `intent + advisory_scope`. claims/manifest는 자동.
|
|
32
|
+
- hook 단일소스 = spec md(정책/등록/테스트) + 정본 알고리즘. form=`core_adapter`(대부분: `{id}_core.py` pure core
|
|
33
|
+
+ `adapters/{claude,codex}/{id}.sh`) / `native`(write-guard: 단일 `{id}.sh`).
|
|
34
|
+
- enforcement는 hook 전용. agent/skill은 advisory_scope만.
|
|
35
|
+
- 수정은 항상 여기(spec)부터 → `sage generate`. 산출물 직접수정은 block → `sage absorb`.
|
|
36
|
+
- 승인은 `auto_approve_safe_default`(conformance/hash PASS면 자동, 예외만 사람).
|
|
37
|
+
|
|
38
|
+
## claims (자동도출)
|
|
39
|
+
|
|
40
|
+
`.claude`/`.codex` 두 산출물의 **typed claim 교집합** = required, 명시 부정문 + AGENT_GUIDE 경계
|
|
41
|
+
참조 = forbidden, 차집합 분류 = runtime_delta_allowlist.
|
|
42
|
+
confidence: `high`(양쪽) / `source_supported`(권위출처) / `runtime_allowed`(allowlist) / `unresolved`(사람).
|
|
43
|
+
conformance PASS/FAIL은 deterministic checker만 (LLM judge 금지).
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: capture-declared-risk
|
|
3
|
+
kind: hook
|
|
4
|
+
runtime_bindings:
|
|
5
|
+
claude: { event: UserPromptSubmit, matcher: "", timeout: 5 }
|
|
6
|
+
codex: { event: UserPromptSubmit, matcher: "", timeout: 5 }
|
|
7
|
+
---
|
|
8
|
+
## intent
|
|
9
|
+
유저 프롬프트에서 명시적 risk level 선언(L0~L3)을 포착해 세션별로 저장한다.
|
|
10
|
+
pre-implementation-gate 가 읽어 effective level = max(감지, 선언)으로 게이트를 적용한다
|
|
11
|
+
(선언은 상향만 — 안전 바닥 유지).
|
|
12
|
+
|
|
13
|
+
## runtime_bindings
|
|
14
|
+
- claude: { event: UserPromptSubmit, input: stdin JSON(prompt, session_id), output: plain text(stdout) }
|
|
15
|
+
- codex: { event: UserPromptSubmit, input: stdin JSON(prompt, session_id), output: hookSpecificOutput JSON }
|
|
16
|
+
- on_fail: 없음 (capture/noop 모두 exit 0)
|
|
17
|
+
|
|
18
|
+
## canonical
|
|
19
|
+
scripts/sage_harness/hooks/capture_declared_risk_core.py → decide(event) -> decision
|
|
20
|
+
- 알고리즘(공유): 위험레벨 정규식 2패턴, 세션 sanitize, 2일 cleanup 선언, state {level, ts, excerpt}
|
|
21
|
+
- core 는 IO/시간호출 없음. now_utc 는 adapter 주입.
|
|
22
|
+
|
|
23
|
+
## adapter_contract
|
|
24
|
+
- contract_version: "1"
|
|
25
|
+
- 표준 event: { hook_id, hook_event_name, runtime, session_id, prompt, now_utc }
|
|
26
|
+
- 표준 decision: { kind, action(capture|noop), level, session_key, state_file, state, cleanup, exit_code, message_key }
|
|
27
|
+
- adapter 책임 3종:
|
|
28
|
+
1. 입력추출: 런타임 stdin JSON → 표준 event
|
|
29
|
+
2. 출력렌더: claude=plain text / codex=hookSpecificOutput JSON (메시지 텍스트는 런타임 프로토콜 — adapter 소유)
|
|
30
|
+
3. 경로·env 바인딩 + 파일IO: CLAUDE_PROJECT_DIR/.claude/logs vs CODEX_PROJECT_ROOT/.codex/logs
|
|
31
|
+
|
|
32
|
+
## reverse_extract 분류 (7범주)
|
|
33
|
+
- token_adapter: PROJECT_ROOT env명, 로그경로(.claude↔.codex)
|
|
34
|
+
- output_adapter: plain text ↔ hookSpecificOutput JSON, 메시지 텍스트(이모지/구두점)
|
|
35
|
+
- algorithm(공유): 레벨 정규식·cleanup·state — core 로 승격
|
|
36
|
+
- noise(정규화): 주석, 따옴표 스타일, import 정렬
|
|
37
|
+
- algorithm_delta/policy_delta/unresolved: **없음** (이 hook 은 순수 token+output adapter — 드리프트 없음)
|
|
38
|
+
|
|
39
|
+
## tests
|
|
40
|
+
scripts/sage_harness/hooks/tests/test_capture_declared_risk.py
|
|
41
|
+
- core decision parity (fixture 3종)
|
|
42
|
+
- adapter end-to-end exit/state/output snapshot (claude·codex)
|
|
43
|
+
- now_utc 고정(SAGE_NOW_UTC)으로 timestamp 결정론
|