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
213 changes: 209 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,16 @@ jobs:
- run: scriptorium --version
- run: scriptorium init --help
- run: scriptorium inventory --help
- run: scriptorium migrate --help
- run: scriptorium resume --help
- run: scriptorium status --help
- run: scriptorium doctor --help
- run: scriptorium host install --help
- run: scriptorium components --profile core --json
- run: scriptorium install core --target ./scriptorium-components-preview --json
- run: python -m unittest discover -s tests -v
- name: Run general project intake acceptance
run: python tests/e2e_general_intake.py

e2e-windows:
runs-on: windows-latest
Expand All @@ -39,34 +45,85 @@ jobs:
with:
path: scriptorium
persist-credentials: false
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
ref: v0.1.0
path: scriptorium-v0.1.0
persist-credentials: false
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
repository: scriptorium-suite/scriptorium-spec
ref: 66bfefea93758231491fadc4694708d1b8107ea0
ref: 36612e80c49f5a8f346a09ed73f4b1c67cef5135
path: scriptorium-spec
persist-credentials: false
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
repository: scriptorium-suite/steward
ref: 21e4e454fb97702bc5f31c24b805cf3c9489bc31
ref: 7aafad1b432207905072c769fe527a3d4d1b365e
path: steward
persist-credentials: false
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
repository: foxsplendid/Provenance
ref: 910efbc47e604c51314866174581cfdd7eac47b6
ref: 1e3f1c022148c33f257d8a27502b50dbe906611d
path: Provenance
persist-credentials: false
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
repository: foxsplendid/Academic-Slides-Agent
ref: 6371f1e6eac41f505aed39e58dafb689317cab65
path: Academic-Slides-Agent
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.12"
- name: Install pinned build backend
run: >-
python -m pip install
--disable-pip-version-check
--no-deps
--only-binary=:all:
"setuptools==83.0.0"
- name: Verify clean Windows install lifecycle
shell: pwsh
run: |
python .\scriptorium\tests\e2e_install_lifecycle.py `
--scriptorium-root .\scriptorium `
--spec-root .\scriptorium-spec `
--steward-root .\steward `
--provenance-root .\Provenance `
--previous-scriptorium-root .\scriptorium-v0.1.0 `
--require-windows `
--report .\install-lifecycle-report.json
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }

$report = Get-Content -LiteralPath .\install-lifecycle-report.json -Raw | ConvertFrom-Json
if (
$report.status -ne "passed" -or
$report.lifecycle.clean_install -ne "passed" -or
$report.lifecycle.uninstall -ne "passed" -or
$report.lifecycle.reinstall -ne "passed" -or
$report.lifecycle.standalone_components -ne "passed" -or
$report.lifecycle.doctor_and_demo -ne "passed" -or
$report.lifecycle.version_transition.status -ne "passed" -or
$report.lifecycle.version_transition.previous_version -ne "0.1.0"
) {
throw "Clean Windows install lifecycle did not pass"
}
- name: Install uv for Lectern
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
with:
version: "0.11.16"
python-version: "3.12.3"
- name: Install source checkouts
shell: pwsh
run: |
python -m venv .demo-venv
.\.demo-venv\Scripts\python.exe -m pip install --no-deps .\scriptorium
.\.demo-venv\Scripts\python.exe -m pip install --no-deps .\steward
.\.demo-venv\Scripts\python.exe -m pip install --no-deps .\Provenance
- name: Install Lectern workspace without provider extras
run: uv sync --project .\Academic-Slides-Agent --all-packages --locked --no-dev
- name: Smoke installed public pull entries
shell: pwsh
run: |
Expand All @@ -78,6 +135,13 @@ jobs:
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
& .\.demo-venv\Scripts\prov-sync-unresolved.exe --help | Out-Null
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
& .\.demo-venv\Scripts\prov-ingest-research.exe --help | Out-Null
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
$contextVersion = & .\.demo-venv\Scripts\prov-context.exe --version
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
if (($contextVersion -join "`n").Trim() -ne '0.18.0') {
throw "Installed Provenance context runtime version mismatch"
}

$raw = & .\.demo-venv\Scripts\prov-sync-pull.exe --capabilities --json
$code = $LASTEXITCODE
Expand All @@ -98,8 +162,12 @@ jobs:
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
& .\.demo-venv\Scripts\scriptorium.exe inventory --help | Out-Null
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
& .\.demo-venv\Scripts\scriptorium.exe migrate --help | Out-Null
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
& .\.demo-venv\Scripts\scriptorium.exe status --help | Out-Null
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
& .\.demo-venv\Scripts\scriptorium.exe resume --help | Out-Null
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }

$errorRaw = & .\.demo-venv\Scripts\scriptorium.exe pull --json 2>$null
$errorCode = $LASTEXITCODE
Expand Down Expand Up @@ -163,12 +231,148 @@ jobs:
if ([IO.File]::ReadAllText((Join-Path $source 'private-note.md')) -ne 'PRIVATE_RESEARCH_SENTINEL') {
throw "Inventory modified a source file"
}
- name: Smoke installed synthetic migration lifecycle
shell: pwsh
run: |
$root = Join-Path $env:RUNNER_TEMP 'migration smoke'
$source = Join-Path $root 'selected source'
$workspace = Join-Path $root 'research workspace'
$env:LOCALAPPDATA = Join-Path $root 'canonical local state'
New-Item -ItemType Directory -Path $source, $workspace | Out-Null

[IO.File]::WriteAllText(
(Join-Path $source 'synthetic-note.md'),
'# SYNTHETIC_MIGRATION_SENTINEL'
)
[IO.File]::WriteAllText(
(Join-Path $source 'synthetic-paper.pdf'),
'%PDF-1.4 SYNTHETIC'
)

$planRaw = & .\.demo-venv\Scripts\scriptorium.exe migrate plan `
--source $source `
--workspace $workspace `
--batch-id synthetic-ci `
--json
if ($LASTEXITCODE -ne 0) { throw "Installed migration plan failed" }
$planSerialized = $planRaw -join "`n"
$plan = $planSerialized | ConvertFrom-Json
if (
$plan.operation -ne 'plan' -or
$plan.status -ne 'planned' -or
$plan.summary.files -ne 2
) {
throw "Installed migration plan report changed"
}
if (Test-Path (Join-Path $workspace 'Sources')) {
throw "Migration plan wrote into the workspace"
}
if (Test-Path $env:LOCALAPPDATA) {
throw "Migration plan persisted private state"
}

$applyRaw = & .\.demo-venv\Scripts\scriptorium.exe migrate apply `
--source $source `
--workspace $workspace `
--batch-id synthetic-ci `
--json
if ($LASTEXITCODE -ne 0) { throw "Installed migration apply failed" }
$applySerialized = $applyRaw -join "`n"
$apply = $applySerialized | ConvertFrom-Json
if (
$apply.operation -ne 'apply' -or
$apply.status -ne 'applied' -or
$apply.summary.changed -ne 2
) {
throw "Installed migration apply report changed"
}

$verifyRaw = & .\.demo-venv\Scripts\scriptorium.exe migrate verify `
--workspace $workspace `
--batch-id synthetic-ci `
--json
if ($LASTEXITCODE -ne 0) { throw "Installed migration verify failed" }
$verify = ($verifyRaw -join "`n") | ConvertFrom-Json
if ($verify.operation -ne 'verify' -or $verify.status -ne 'applied') {
throw "Installed migration verify report changed"
}

$repeatRaw = & .\.demo-venv\Scripts\scriptorium.exe migrate apply `
--workspace $workspace `
--batch-id synthetic-ci `
--json
if ($LASTEXITCODE -ne 0) { throw "Installed migration reapply failed" }
$repeat = ($repeatRaw -join "`n") | ConvertFrom-Json
if ($repeat.status -ne 'unchanged') {
throw "Installed migration reapply was not idempotent"
}

$rollbackRaw = & .\.demo-venv\Scripts\scriptorium.exe migrate rollback `
--workspace $workspace `
--batch-id synthetic-ci `
--json
if ($LASTEXITCODE -ne 0) { throw "Installed migration rollback failed" }
$rollbackSerialized = $rollbackRaw -join "`n"
$rollback = $rollbackSerialized | ConvertFrom-Json
if (
$rollback.operation -ne 'rollback' -or
$rollback.status -ne 'rolled-back' -or
$rollback.summary.changed -ne 2
) {
throw "Installed migration rollback report changed"
}

$allReports = @(
$planSerialized,
$applySerialized,
($verifyRaw -join "`n"),
($repeatRaw -join "`n"),
$rollbackSerialized
) -join "`n"
foreach ($privateValue in @(
$root,
$source,
$workspace,
'synthetic-note.md',
'synthetic-paper.pdf',
'SYNTHETIC_MIGRATION_SENTINEL'
)) {
if ($allReports.Contains($privateValue)) {
throw "Migration report exposed a private source value"
}
}
if (
[IO.File]::ReadAllText((Join-Path $source 'synthetic-note.md')) -ne
'# SYNTHETIC_MIGRATION_SENTINEL'
) {
throw "Migration modified its source"
}
$remaining = @(
Get-ChildItem `
(Join-Path $workspace 'Sources\Imported\synthetic-ci') `
-File `
-Recurse `
-ErrorAction SilentlyContinue
)
if ($remaining.Count -ne 0) {
throw "Migration rollback left owned files"
}
- name: Run isolated public pull E2E
shell: pwsh
run: |
& .\.demo-venv\Scripts\python.exe `
.\scriptorium\tests\e2e_pull.py `
--provenance-root .\Provenance
--provenance-root .\Provenance `
--spec-root .\scriptorium-spec
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
- name: Run offline Steward to Lectern golden path
shell: pwsh
run: |
& .\.demo-venv\Scripts\python.exe `
.\scriptorium\tests\e2e_slides.py `
--steward-root .\steward `
--spec-root .\scriptorium-spec `
--lectern-root .\Academic-Slides-Agent
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
- name: Run credential-free golden path
shell: pwsh
Expand All @@ -194,4 +398,5 @@ jobs:
path: |
demo 输出
doctor-report.json
install-lifecycle-report.json
retention-days: 14
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ htmlcov/
build/
dist/
scriptorium-demo/
.tmp-*/

# Local configuration and credentials
.env
Expand Down
40 changes: 37 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,38 @@
# Changelog

## 0.2.0 (candidate) — 2026-07-22

- Add `scriptorium resume`, backed by Provenance's bounded, read-only Context
Capsule. It restores approved project state, explicitly labels auto-applied
low-risk progress, and keeps literature artifacts reference-only.
- Extend the synthetic demo with all four literature-reading artifacts, atomic
idempotent ingestion, reference hints, and privacy assertions.
- Exercise a synthetic software project through Codex and Claude Code workspace
adapters, proving that fresh processes recover the same reviewed project state.
- Require compatible `prov-context` and `prov-ingest-research` commands in Public
Alpha diagnostics, including an actual runtime-version probe.
- Move the candidate compatibility baseline to `scriptorium-spec` 2.3.0 for the
additive `project/1.1` profile field while retaining `project/1.0` compatibility.
- Add pinned `core`, `research`, `slides`, `full`, and `capture` component profiles;
add a preview-first source installer and an independently downloadable Capture
Release asset path without splitting Capture into another repository.
- Add general, engineering, software, and research project templates. Experimental
run/evidence promotion remains on development branches and outside stable-core
acceptance.
- Add the safety-reviewed `scriptorium migrate` CLI to the stable-core candidate for
explicit Markdown/PDF copies: write-free plan, create-if-absent apply,
canonical private state, cross-process verify/reapply recovery, and rollback.
Reports and errors remain aggregate-only and path-free; linked repositories stay
authoritative and are registered rather than copied wholesale.
- Add an offline, synthetic Steward-to-Lectern acceptance path that validates a
two-paper handoff through Lectern's production graph, stops for outline approval
with no persistent pre-approval PPTX, compiles an editable deck, and
scans transferable artifacts for paths, email addresses, and credential shapes.
- Add a temporary clean-environment lifecycle gate that builds local wheels with
package indexes disabled, verifies install/uninstall/reinstall and the synthetic
demo, and exercises the public v0.1.0-to-current version transition. Live Agent,
PowerPoint, external-user, and fresh remote-CI acceptance remain explicit gates.

## 0.1.0 — 2026-07-20

- Add `scriptorium inventory`, a deterministic, zero-write preview for explicitly
Expand Down Expand Up @@ -34,7 +67,7 @@
- Add the content-free `scriptorium status` control-plane summary over trusted
doctor and pull-preview reports. It exposes allowlisted readiness, freshness,
aggregate backlog counts, and fixed review cues without forwarding paths,
identifiers, research content, stderr, or an implicit `--run` authorization.
identifiers, project content, stderr, or an implicit `--run` authorization.
It authorizes no suite project/data writes while accurately disclosing external
readiness probes.
- Report content-free path-selection provenance across `doctor`, `pull`, and
Expand All @@ -50,8 +83,9 @@
subprocesses cannot reuse the user's real application configuration or caches.
- Document verified product-design inspirations, independent implementation boundaries,
current capability gaps, and the policy for future third-party reuse.
- Wire the canonical research skill to the aggregate `agent-fill` / `project-resolution`
actions through read-only unresolved inspection, allowlisted scaffold reads, and an
- Wire the canonical project skill (with its compatibility-preserved directory name)
to the aggregate `agent-fill` / `project-resolution` actions through read-only
unresolved inspection, allowlisted scaffold reads, and an
atomic credential-checked fill command; candidate and authoritative writes require
separate approval and protected paths are never constructed by the skill.
- Refuse unresolved-project session summaries and preserve those events for explicit,
Expand Down
Loading