Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 10 additions & 66 deletions README.ko.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

Savepoint는 이전 대화 컨텍스트에 의존하지 않고 새 코딩 에이전트가 현재 repo/Git 상태에서 이어갈 수 있게 `.savepoint/SAVEPOINT.md`를 생성하거나 검증하는 skill입니다.

Savepoint는 가벼운 대화 요약이 아닙니다. 복구 가능한 repo/Git checkpoint입니다. 파일 복구가 필요 없으면 `/savepoint text`나 일반 요약을 사용하세요.

## 30초 사용법

```text
Expand Down Expand Up @@ -34,7 +36,7 @@ Savepoint는 이전 대화 컨텍스트에 의존하지 않고 새 코딩 에이

- file mode는 `.savepoint/SAVEPOINT.md`를 씁니다.
- artifact는 repo/Git snapshot, `## Resume Prompt`, 마지막 `SAVEPOINT_V1` marker block을 포함합니다.
- `REDACTION_CHECKED: yes` 전에 생성된 artifact의 secret-like 값을 스캔합니다.
- `REDACTION_CHECKED: yes` 전에 generated artifact를 pattern-based secret-like scan으로 검사합니다.
- bundled validator가 marker shape와 safe-resume 필드를 검사합니다.
- load 시 현재 disk state가 savepoint text보다 우선합니다.

Expand All @@ -46,17 +48,7 @@ Savepoint는 이전 대화 컨텍스트에 의존하지 않고 새 코딩 에이
- 미래 충돌 없음
- text mode만으로 repo 상태를 복구할 수 있음

## Runtime command

public entrypoint는 다음입니다.

```bash
python3 scripts/savepoint.py save --input .savepoint/input.json --output .savepoint/SAVEPOINT.md --assert-no-active-commands --scan-redaction --validate
python3 scripts/savepoint.py init-input --output .savepoint/input.json
python3 scripts/savepoint.py validate .savepoint/SAVEPOINT.md
python3 scripts/savepoint.py inspect .savepoint/SAVEPOINT.md --json
python3 scripts/savepoint.py text --input .savepoint/input.json
```
## 최소 CLI 흐름

portable skill entrypoint는 `skills/savepoint/scripts/savepoint.py`입니다. repository-local 명령은 `scripts/savepoint.py`를 사용합니다.

Expand All @@ -71,42 +63,7 @@ python3 scripts/savepoint.py save --input .savepoint/input.json --output .savepo
python3 scripts/savepoint.py inspect .savepoint/SAVEPOINT.md --json
```

짧은 savepoint를 JSON 편집 없이 만들 때:

```bash
python3 scripts/savepoint.py save \
--output .savepoint/SAVEPOINT.md \
--assert-no-active-commands --scan-redaction --validate \
--goal "focused fix 마무리" \
--current-state "구현은 끝난 상태" \
--next-action "최종 검증 suite 실행" \
--project-status passed \
--validation-command "python3 scripts/check-savepoint-renderer.py" \
--validation-result passed \
--validation-summary "focused renderer checks passed"
```

`--scan-redaction`을 쓰면 입력 JSON을 렌더 전에 먼저 스캔합니다. `.savepoint/input.json`에 raw secret을 넣지 마세요. `--delete-input-on-success`를 추가하면 resume-ready save가 성공했을 때만 `.savepoint/input.json`을 삭제합니다.

기존 자동화도 `scripts/savepoint.py`를 호출하게 바꿉니다.

| 이전 호출 | 현재 호출 |
|---|---|
| `scripts/render_savepoint.py --input ...` | `scripts/savepoint.py save --input ...` |
| `scripts/validate_savepoint.py ...` | `scripts/savepoint.py validate ...` |

프로젝트 검증 입력은 `validation.project`를 사용합니다.

| 이전 key | 현재 field |
|---|---|
| `project_validation` | `validation.project.commands`와 `validation.project.status` |
| `skipped_checks_next_validation` | `validation.project.next_validation` |
| `smallest_next_step` | `next_action` |
| `blockers` | `unresolved_blockers` |

`failed-expected` 또는 `not-run-justified`를 쓰면 사유와 다음 검증 명령을 함께 기록합니다.

`validation.project.status`는 문서에 나열된 영어 값을 사용합니다. 검증 명령 `result`는 `passed` 또는 `failed`처럼 canonical English 값을 쓰고, summary와 reason은 한국어도 괜찮습니다.
`validation.project.status`는 `passed`, `failed-expected`, `failed-blocking`, `not-run-justified`, `not-run-unknown` 중 하나를 사용합니다. `--scan-redaction`을 쓰면 입력 JSON을 렌더 전에 스캔합니다. `.savepoint/input.json`에 raw secret을 넣지 마세요.

## 설치

Expand Down Expand Up @@ -142,24 +99,11 @@ examples, evals, maintainer docs, repository validation scripts는 일반 agent
- `examples/text-note/`: response-only `/savepoint text` 예시
- `examples/unsafe-savepoint/`: 의도적으로 unsafe한 `RESUME_READY: no` artifact

## Maintainer validation
## Maintainer docs

생성된 artifact는 `scripts/savepoint.py validate .savepoint/SAVEPOINT.md`로 검증합니다.

`scripts/validate-repo.py`는 이 저장소를 유지보수할 때만 사용합니다. packaging, examples, trigger evals, marker/schema contracts를 검사합니다.

커밋 전에는 다음을 실행합니다.

```bash
python3 scripts/check-frontmatter.py
python3 scripts/check-marker-block.py
python3 scripts/check-marker-semantics.py
python3 scripts/validate-examples.py
python3 scripts/check-output-contract.py
python3 scripts/validate-repo.py
python3 scripts/check-savepoint-renderer.py
python3 scripts/check-install-helper.py
python3 scripts/savepoint.py validate --allow-example-paths examples/SAVEPOINT.filled.example.md examples/file-bugfix/SAVEPOINT.md examples/file-architecture/SAVEPOINT.md examples/unsafe-savepoint/SAVEPOINT.md
python3 -m compileall -q skills/savepoint/scripts scripts
git diff --check
```
- repository 변경 검증: `AGENTS.md`
- marker와 safe-resume semantics: `docs/reference/savepoint-contract.md`
- compact packaging 기준: `docs/reference/context-packaging.md`
- 수동 artifact fallback: `docs/reference/savepoint-template.md`
83 changes: 10 additions & 73 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

Savepoint creates or verifies a recoverable coding-session checkpoint so a fresh agent can continue from current repo/Git state without prior chat context.

Savepoint is not a lightweight conversation summary. It is a recoverable repo/Git checkpoint; use `/savepoint text` or an ordinary summary when file recovery is unnecessary.

## 30-second usage

```text
Expand Down Expand Up @@ -34,7 +36,7 @@ If a client does not pass custom slash prompts through, use the natural-language

- File mode writes `.savepoint/SAVEPOINT.md`.
- The artifact includes a repo/Git snapshot, `## Resume Prompt`, and one final `SAVEPOINT_V1` marker block.
- Generated artifacts are scanned for secret-like values before `REDACTION_CHECKED: yes`.
- Generated artifacts receive pattern-based secret-like scans before `REDACTION_CHECKED: yes`.
- The bundled validator checks marker shape and safe-resume fields.
- On load, current disk state wins over savepoint text.

Expand All @@ -46,17 +48,7 @@ If a client does not pass custom slash prompts through, use the natural-language
- Future conflicts are impossible.
- Repo recovery from text mode.

## Runtime command

The public entrypoint is:

```bash
python3 scripts/savepoint.py save --input .savepoint/input.json --output .savepoint/SAVEPOINT.md --assert-no-active-commands --scan-redaction --validate
python3 scripts/savepoint.py init-input --output .savepoint/input.json
python3 scripts/savepoint.py validate .savepoint/SAVEPOINT.md
python3 scripts/savepoint.py inspect .savepoint/SAVEPOINT.md --json
python3 scripts/savepoint.py text --input .savepoint/input.json
```
## Minimal CLI workflow

The portable skill entrypoint is `skills/savepoint/scripts/savepoint.py`; repository-local commands use `scripts/savepoint.py`.

Expand All @@ -71,42 +63,7 @@ python3 scripts/savepoint.py save --input .savepoint/input.json --output .savepo
python3 scripts/savepoint.py inspect .savepoint/SAVEPOINT.md --json
```

For a short savepoint without editing JSON:

```bash
python3 scripts/savepoint.py save \
--output .savepoint/SAVEPOINT.md \
--assert-no-active-commands --scan-redaction --validate \
--goal "finish the focused fix" \
--current-state "implementation is done" \
--next-action "run the final validation suite" \
--project-status passed \
--validation-command "python3 scripts/check-savepoint-renderer.py" \
--validation-result passed \
--validation-summary "focused renderer checks passed"
```

With `--scan-redaction`, the input JSON is scanned before rendering. Do not put raw secrets in `.savepoint/input.json`. Add `--delete-input-on-success` to remove `.savepoint/input.json` only after a resume-ready save succeeds.

Existing automation should call `scripts/savepoint.py`. Update old root-wrapper calls as:

| Old call | Current call |
|---|---|
| `scripts/render_savepoint.py --input ...` | `scripts/savepoint.py save --input ...` |
| `scripts/validate_savepoint.py ...` | `scripts/savepoint.py validate ...` |

Use `validation.project` for project validation input. Replace old top-level input keys as:

| Old key | Current field |
|---|---|
| `project_validation` | `validation.project.commands` plus `validation.project.status` |
| `skipped_checks_next_validation` | `validation.project.next_validation` |
| `smallest_next_step` | `next_action` |
| `blockers` | `unresolved_blockers` |

For `failed-expected` or `not-run-justified`, include the reason and next validation command.

Use the listed English `validation.project.status` values. Validation command `result` should use canonical English values such as `passed` or `failed`; summaries and reasons may be any language.
Use `validation.project.status` values `passed`, `failed-expected`, `failed-blocking`, `not-run-justified`, or `not-run-unknown`. With `--scan-redaction`, the input JSON is scanned before rendering; do not put raw secrets in `.savepoint/input.json`.

## Install

Expand All @@ -124,13 +81,6 @@ The helper defaults to dry-run. It writes files only with `--apply`. With repo-s

On Windows, prefer the install helper or a normal Git clone/worktree. Archive extraction tools can mishandle symlinks.

Typical skill locations:

- Codex user skill: `$HOME/.agents/skills/savepoint/`
- Codex repo skill: `<repo>/.agents/skills/savepoint/`
- Claude user skill: `$HOME/.claude/skills/savepoint/`
- Claude project skill: `<repo>/.claude/skills/savepoint/`

## Runtime boundary

Normal create/load should use only:
Expand All @@ -149,27 +99,14 @@ Examples, evals, maintainer docs, and repository validation scripts are not norm
- `examples/text-note/`: response-only `/savepoint text` note.
- `examples/unsafe-savepoint/`: intentionally unsafe `RESUME_READY: no` artifact.

## Maintainer validation
## Maintainer docs

Use `scripts/savepoint.py validate .savepoint/SAVEPOINT.md` for generated artifacts.

Use `scripts/validate-repo.py` only for maintaining this repository. It checks packaging, examples, trigger evals, and marker/schema contracts.

Before committing repository changes, run:

```bash
python3 scripts/check-frontmatter.py
python3 scripts/check-marker-block.py
python3 scripts/check-marker-semantics.py
python3 scripts/validate-examples.py
python3 scripts/check-output-contract.py
python3 scripts/validate-repo.py
python3 scripts/check-savepoint-renderer.py
python3 scripts/check-install-helper.py
python3 scripts/savepoint.py validate --allow-example-paths examples/SAVEPOINT.filled.example.md examples/file-bugfix/SAVEPOINT.md examples/file-architecture/SAVEPOINT.md examples/unsafe-savepoint/SAVEPOINT.md
python3 -m compileall -q skills/savepoint/scripts scripts
git diff --check
```
- Repository change validation: `AGENTS.md`.
- Marker and safe-resume semantics: `docs/reference/savepoint-contract.md`.
- Compact packaging guidance: `docs/reference/context-packaging.md`.
- Manual artifact fallback: `docs/reference/savepoint-template.md`.

## Orchestrators

Expand Down
60 changes: 45 additions & 15 deletions scripts/validate-repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,8 +264,8 @@ def validate_frontmatter(self) -> None:
if phrase not in description:
self.fail(f"frontmatter description must include Korean invocation phrase: {phrase}")
body = "\n".join(lines[end + 1 :])
if not body.strip().startswith("# Savepoint"):
self.fail("SKILL.md body should start with '# Savepoint'")
if not body.strip().startswith("Modes:"):
self.fail("SKILL.md body should start with mode definitions")

def validate_references(self) -> None:
skill_text = self.read(SKILL_DIR / "SKILL.md")
Expand All @@ -284,30 +284,44 @@ def validate_references(self) -> None:
self.fail(f"root wrapper should not exist: scripts/{removed_wrapper}")

required_skill_phrases = [
"Default behavior",
"/savepoint -> create or refresh `.savepoint/SAVEPOINT.md`",
"/savepoint save",
"/savepoint load",
"/savepoint text",
"Modes:",
"default or `save`: create or refresh `.savepoint/SAVEPOINT.md`",
"`load`: verify an existing savepoint and report whether continuation is safe",
"`text`: response-only copy-paste handoff; no file recovery guarantee",
".savepoint/SAVEPOINT.md",
"SAVEPOINT_V1",
"RESUME_READY: yes",
"Do not read references, `scripts/*.py`, or `evals/*.json` during normal use.",
"Run the bundled CLI; do not inspect implementation source during normal use.",
"Resolve `<savepoint-skill-dir>` before running commands",
"python3 <savepoint-skill-dir>/scripts/savepoint.py save",
"inspect <path> --json",
"append `--force` only when",
"generated, untracked, valid default artifact",
"`validation.project.status`",
"`not-run-justified`",
"`failed-expected`",
"`no-file`, `no files`, `in-response`, or `in the response`",
"Prepare `.savepoint/input.json` as in Save, then run",
"## Load / Resume",
"For inspect-only requests, do not clean up by default.",
"Continue only when the user requested continuation and `RESUME_READY` is `yes`",
"Read `references/contract.md` only when",
"Read references only when normal CLI use is insufficient",
"`references/contract.md`",
"`references/safety.md`",
"`references/template.md`",
]
for phrase in required_skill_phrases:
if phrase not in skill_text:
self.fail(f"SKILL.md missing required policy: {phrase}")
skill_line_count = len(skill_text.splitlines())
if skill_line_count > 55:
self.fail(f"SKILL.md should stay concise at <=55 lines, got {skill_line_count}")
for phrase in [
"direct flags such as",
"do not combine direct flags",
]:
if phrase in skill_text:
self.fail(f"SKILL.md should not include CLI shortcut detail: {phrase}")

contract_text = self.read(REFERENCE_DIR / "savepoint-contract.md")
for phrase in [
Expand Down Expand Up @@ -383,9 +397,10 @@ def validate_readme_format(self) -> None:
"Savepoint",
".savepoint/SAVEPOINT.md",
"scripts/savepoint.py",
"scripts/check-output-contract.py",
"scripts/validate-repo.py",
"python3 -m compileall",
"AGENTS.md",
"docs/reference/savepoint-contract.md",
"Savepoint is not a lightweight conversation summary.",
"pattern-based secret-like scans",
]:
if phrase not in readme_text:
self.fail(f"README.md missing entry: {phrase}")
Expand All @@ -399,12 +414,27 @@ def validate_readme_format(self) -> None:
"Savepoint",
".savepoint/SAVEPOINT.md",
"scripts/savepoint.py",
"scripts/check-output-contract.py",
"scripts/validate-repo.py",
"python3 -m compileall",
"AGENTS.md",
"docs/reference/savepoint-contract.md",
"Savepoint는 가벼운 대화 요약이 아닙니다.",
"pattern-based secret-like scan",
]:
if phrase not in readme_ko_text:
self.fail(f"README.ko.md missing entry: {phrase}")
for phrase in [
"Old call",
"Old key",
"Before committing repository changes, run:",
]:
if phrase in readme_text:
self.fail(f"README.md should not carry maintainer/migration detail: {phrase}")
for phrase in [
"이전 호출",
"이전 key",
"커밋 전에는 다음을 실행합니다.",
]:
if phrase in readme_ko_text:
self.fail(f"README.ko.md should not carry maintainer/migration detail: {phrase}")

def validate_agent_metadata(self) -> None:
path = SKILL_DIR / "agents" / "openai.yaml"
Expand Down
Loading
Loading