Governance harness for AI coding agents — spec-SSOT closed loop for Claude Code and Codex
Project description
SAGE — System for Agentic Governance & Engineering
AI 코딩 에이전트를 위한 거버넌스 하네스. 자산마다 spec 파일 하나 — SAGE가 런타임 설정을 생성하고, drift를 검증하고, hook이 실행 시점에 위반을 차단합니다. Claude Code와 Codex 양쪽에서 동작합니다.
왜 SAGE인가
AI 에이전트는 빠르지만 규칙을 조용히 어깁니다:
- plan 문서 없이 고위험 파일을 수정한다
- PDCA 단계를 건너뛴다
- 생성된 산출물을 손으로 덮어쓴다
- 자기 코드를 자기 모델로 리뷰한다 (단일 모델 편향)
보통은 사람이 매번 잔소리하거나, 프로젝트마다 .claude/·.codex/ 설정을 손으로 관리합니다. SAGE는 그 두 가지를 spec-SSOT 폐루프로 대체합니다.
빠른 시작 (30초)
pip install sage-harness
cd your-project
sage install # 런타임 선택: claude 또는 codex
# hook·에이전트 spec·AGENT_GUIDE·manifest 자동 배치
sage generate # spec md → .claude/.codex 산출물 + manifest 스탬프
sage validate # drift · staleness · conformance 검사 (읽기 전용)
끝입니다. 이제 AI 에이전트는 강제력 있는 규칙 위에서 동작합니다.
동작 원리
사람이 의도를 쓴다 generate 런타임에 배치 validate / hook 게이트
docs/.../hooks/{id}.md ──────────► .claude/hooks/ ──────────► 위반 시 BLOCK
docs/.../agents/{id}.md .codex/agents/ drift 시 validate FAIL
docs/.../mcps/{id}.md .mcp.json │
▲ manifest 스탬프 │
└────────────── absorb (직접수정 → spec patch 제안) ─────────────┘
핵심은 폐루프입니다 — spec에서 산출물을 만들고(generate), 산출물이 spec과 어긋나면 잡아냅니다(validate), 산출물을 직접 수정하면 차단하고(write-guard), 비상 수정분은 다시 spec으로 흡수 제안합니다(absorb).
엔진 자체에는 도메인 값이 0개입니다 — 스택·위험 경로·PDCA 키워드는 전부 sage/project-profile.yaml에서 주입됩니다. 프로필만 바꾸면 같은 엔진이 다른 스택을 거버넌스합니다.
자산 종류 4종
| kind | 생성 성격 | SSOT | 산출물 |
|---|---|---|---|
hook |
결정론 (순수 함수) | docs/sage_harness/hooks/{id}.md + {id}_core.py |
settings.json / hooks.json + 런타임 shim |
agent |
interpretive (AI 렌더) | docs/sage_harness/agents/{id}.md + {id}.claims.yml |
.claude/agents/ / .codex/agents/ |
skill |
interpretive (AI 렌더) | docs/sage_harness/skills/{id}.md + {id}.claims.yml |
.claude/skills/ / .codex/skills/ |
mcp |
결정론 (선언 데이터 직렬화) | docs/sage_harness/mcps/{id}.md (frontmatter payload) |
.mcp.json (claude) · .codex/config.toml managed-block (codex) |
MCP 거버넌스: 시크릿은 env 변수명만 허용 (
${VAR}placeholder). 리터럴 시크릿 값이 spec에 있으면 generate 전 FAIL (fail-closed)..mcp.json은 SAGE 소유(write-guard),config.toml의 비-MCP 설정은 보존합니다.
Hook 6종 (무엇을 강제하나)
| hook | 실행 시점 | 역할 |
|---|---|---|
pre-implementation-gate |
파일 수정 전 (PreToolUse) | 위험도 L0–L3 분류 · plan 문서 · PDCA phase 강제. 미충족 시 BLOCK |
pre-phase4-checklist-gate |
단계 전환 전 | PDCA 03→04 전환 시 체크리스트 완료 강제 |
capture-declared-risk |
프롬프트 제출 (UserPromptSubmit) | 유저가 선언한 작업 위험레벨 포착 |
post-tool-logger |
도구 실행 후 (PostToolUse) | 변경 분류를 세션 JSONL에 기록 |
stop-compliance-report |
세션 종료 (Stop) | 컴플라이언스 리포트 생성 |
generated-artifact-write-guard |
파일 수정 전 (native) | 생성 산출물 직접수정 차단 → spec으로 redirect |
Hook은 순수 코어 + 어댑터 구조입니다 — 정책 판정({id}_core.py)은 I/O가 없는 순수 함수이고, 런타임별 I/O는 얇은 어댑터가 담당합니다. 같은 정책, 런타임 간 동일한 동작.
CLI 참조
| 명령 | 역할 |
|---|---|
sage install |
런타임 선택 (claude/codex) · CORE 하네스 배치 (hook·에이전트 spec·AGENT_GUIDE·manifest) |
sage generate |
spec md → 등록 산출물 + {host}/hooks shim + profile 컴파일 + manifest 스탬프 |
sage generate --kind roster |
profile.components → implementer-<comp> 에이전트 spec 결정론 scaffold |
sage generate --kind mcp |
docs/sage_harness/mcps/{id}.md → .mcp.json (claude) / config.toml managed-block (codex) |
sage validate |
drift · staleness · conformance · regression 검사. --check (빠름) / --schema (JSON Schema) |
sage review |
auto_approve_safe_default — 통과는 자동승인, 사람은 예외만 검토 |
sage absorb |
직접수정 diff → spec patch 제안 (자동 반영 없음) |
sage doctor |
옵션 의존성 점검 · 실행 환경 진단 · cross-model reviewer fallback 노출 |
sage change |
자연어 의도 → generate/absorb 라우팅 안내 (v1) |
sage override |
게이트 BLOCK 시한부 합법 우회 + append-only 감사 로그 (.sage/override.jsonl) |
프로필 예시
# sage/project-profile.yaml — 도메인 값은 전부 여기, 엔진에는 0개
project: { name: "acme", prefix: "acme" }
risk:
l1_path_globs: ["*frontend/*.js"] # 저위험 (UI)
l2_path_globs: ["*backend/*.java"] # 소스 (build+test+lint 필요)
l3_filename_globs: ["*payment*", "*auth*"] # 고위험 (plan + 리뷰 필수)
l3_content_keywords: ["encrypt", "PrivateKey", "chargeCard"]
plan_glob: "plan_docs/**/*.md"
components: [backend, frontend] # → sage generate --kind roster
cross_model:
enabled: true
opposite_runtime: codex # phase-05 리뷰를 codex로 실행
cross_model.opposite_runtime: codex 설정 시, 단일 모델이 놓친 P1 이슈를 codex가 실제로 적발한 사례가 있습니다 (weatherapp Tier 2 검증).
설치
PyPI (권장):
pip install sage-harness
JSON Schema 검증 포함:
pip install "sage-harness[schema]"
소스에서 설치 (editable):
git clone https://github.com/SeJonJ/SAGE.git
cd SAGE
pip install -e .
요구사항: Python 3.10+, bash, git.
새 버전 배포
태그를 push하면 publish workflow가 PyPI에 자동 배포합니다:
git tag v0.2.0
git push origin v0.2.0
선행 조건: PyPI에서 Trusted Publisher 등록 (Repository:
SeJonJ/SAGE, Workflow:publish.yml, Environment:release).
이런 분께 맞습니다
아래에 해당하면 SAGE가 맞습니다:
- Claude Code 또는 Codex로 실무 작업 중이고, 에이전트가 규칙을 지키도록 강제하고 싶다
- 프로젝트마다
.claude/·.codex/설정을 손으로 다시 쓰는 게 지쳤다 - Claude + Codex 교차 리뷰(cross-model review) 구조를 갖추고 싶다
- CI에서 검증 가능한 spec 기반 하네스가 필요하다
아래에 해당하면 맞지 않습니다:
- 간단한 프롬프트 팁이 필요한 경우 — SAGE는 프레임워크이지 스니펫이 아닙니다
검증 이력
- 외부검토 1차 하드닝 11항목 완료
- Weatherapp Tier 2 골든 인스턴스:
install → 대화형 부트스트랩 → generate → validate → PDCA phases → cross-model review → 수정 → report전체 파이프라인 실세계 실증 - MCP kind: codex 6라운드 cross-model 리뷰, P0×3 + P1×8 + P2×2 전부 해소, 엔진 도메인 토큰 0
- CI wheel smoke test 강제 (clean venv wheel-only 설치 → generate → validate PASS)
라이선스
MIT — LICENSE 참조.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sage_harness-0.1.0.tar.gz.
File metadata
- Download URL: sage_harness-0.1.0.tar.gz
- Upload date:
- Size: 176.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0908ce3e00d60c016881e08809ef2e91ec40788f78474000f62991056a6a7c12
|
|
| MD5 |
ebdf116825930ea81bbbbfa397c91a66
|
|
| BLAKE2b-256 |
fd52ca6d77083df9cb21186b973a066668ca978410e042653823d3cd759f3db6
|
Provenance
The following attestation bundles were made for sage_harness-0.1.0.tar.gz:
Publisher:
publish.yml on SeJonJ/SAGE
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sage_harness-0.1.0.tar.gz -
Subject digest:
0908ce3e00d60c016881e08809ef2e91ec40788f78474000f62991056a6a7c12 - Sigstore transparency entry: 1879767769
- Sigstore integration time:
-
Permalink:
SeJonJ/SAGE@033f469e32f1d7e812d09f422a235f636174fff2 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/SeJonJ
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@033f469e32f1d7e812d09f422a235f636174fff2 -
Trigger Event:
push
-
Statement type:
File details
Details for the file sage_harness-0.1.0-py3-none-any.whl.
File metadata
- Download URL: sage_harness-0.1.0-py3-none-any.whl
- Upload date:
- Size: 246.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1f83c4e13181b1ed85040448513a9c71f680645406bddd52b3366d1740bc56c9
|
|
| MD5 |
89f4c07079f8bd0c735df45d318b0c64
|
|
| BLAKE2b-256 |
0c6ffd93b3eb3e2fbfd8ebe80f54d89c108e94694e7dde04384a42901d59c840
|
Provenance
The following attestation bundles were made for sage_harness-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on SeJonJ/SAGE
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sage_harness-0.1.0-py3-none-any.whl -
Subject digest:
1f83c4e13181b1ed85040448513a9c71f680645406bddd52b3366d1740bc56c9 - Sigstore transparency entry: 1879767970
- Sigstore integration time:
-
Permalink:
SeJonJ/SAGE@033f469e32f1d7e812d09f422a235f636174fff2 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/SeJonJ
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@033f469e32f1d7e812d09f422a235f636174fff2 -
Trigger Event:
push
-
Statement type: