diff --git a/.codex/hooks.json b/.codex/hooks.json deleted file mode 100644 index df1e946a..00000000 --- a/.codex/hooks.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "description": "Keep task file edits inside the active repository worktree.", - "hooks": { - "PreToolUse": [ - { - "matcher": "^(apply_patch|Bash|Write|Edit|MultiEdit)$", - "hooks": [ - { - "type": "command", - "command": "python3 -B -c \"import pathlib,runpy,subprocess; runpy.run_path(str(pathlib.Path(subprocess.check_output(['git','rev-parse','--show-toplevel'], text=True).strip()) / '.codex/hooks/repository_boundary.py'), run_name='__main__')\"", - "commandWindows": "python -B -c \"import pathlib,runpy,subprocess; runpy.run_path(str(pathlib.Path(subprocess.check_output(['git','rev-parse','--show-toplevel'], text=True).strip()) / '.codex/hooks/repository_boundary.py'), run_name='__main__')\"; exit $LASTEXITCODE", - "timeout": 10, - "statusMessage": "Checking repository write boundary" - } - ] - } - ] - } -} diff --git a/.codex/hooks/README.md b/.codex/hooks/README.md deleted file mode 100644 index 09de367d..00000000 --- a/.codex/hooks/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# Repository write boundary - -Put every task-created temporary file and directory under the active worktree's -`tmp/`. Only `tmp/.gitkeep` is tracked. Use an explicit `dir=` with Python's -temporary-file APIs, and set subprocess `TMPDIR`, `TMP`, and `TEMP` to the -absolute `/tmp/` when a program chooses its own scratch directory. -Read-only access to external inputs is allowed. - -Use Codex's built-in worktree workflow and the worktree attached to the current -chat. Codex manages session permissions; the repository does not require a -particular sandbox profile, another checkout, or an update from `main` before -production. Git and agent applications still manage their own metadata outside -the worktree when their runtime requires it; task-created files belong here. - -The `PreToolUse` hook checks every add, update, delete, and move destination in -`apply_patch`, plus `Write`, `Edit`, and `MultiEdit` file paths. It resolves paths -against the session directory and checks them against the worktree containing -the hook, resolving symlinks and Windows junctions as well. Malformed inputs and -paths outside that root are denied before the edit runs. For shell tools, it -rejects an external working directory and malformed input, while leaving -permission decisions to Codex. It does not parse arbitrary shell programs. - -## Activation - -Python 3.9+ and Git must be on `PATH` (`python` on Windows, `python3` elsewhere). -Use `/hooks` in the CLI to confirm that the repository write boundary is listed, -then review, trust, and enable it; Codex skips new or changed hook definitions -until they are trusted. If it is absent, resolve project hook discovery before -relying on the guard. The launcher finds the Git root so it also works when the -session starts in a repository subdirectory or a Codex-managed worktree. - -Hooks are a guardrail, not a complete filesystem security boundary: some -specialized or hosted tools do not run local tool hooks, and this hook does not -cover every MCP tool. Follow `AGENTS.md` for task files created through shell or -other tools, using the permissions configured in Codex. A Git commit hook cannot block -filesystem writes that happen before a commit. - -See the official [Codex hook protocol](https://developers.openai.com/codex/hooks/) -and [sandbox configuration](https://developers.openai.com/codex/config-reference/). - -## Checks - -From the worktree root, run: - -```text -python -B -m unittest discover -s .codex/hooks -p "test_*.py" -codex doctor --summary -``` - -The tests create all fixtures under this worktree's `tmp/`. They check traversal, -absolute and sibling paths, move destinations, links, malformed requests, shell -working directories, and the hook's denial protocol without writing outside the -repository. diff --git a/.codex/hooks/repository_boundary.py b/.codex/hooks/repository_boundary.py deleted file mode 100644 index 8917032e..00000000 --- a/.codex/hooks/repository_boundary.py +++ /dev/null @@ -1,91 +0,0 @@ -"""Check file-tool paths and shell working directories within this worktree.""" - -import json -import ntpath -import os -from pathlib import Path -import re -import sys - - -ROOT = Path(__file__).resolve().parents[2] -PATCH_PATH = re.compile(r"^\*\*\* (?:Add File|Update File|Delete File|Move to): (.*)$") - - -class BoundaryError(ValueError): - pass - - -def inside(raw, base, root): - """Resolve existing ancestors too, so symlinks and junctions cannot escape.""" - if not isinstance(raw, str) or not raw or any(c in raw for c in "\0\r\n"): - raise BoundaryError("Missing or invalid file path.") - path = Path(raw) - if (path.anchor and not path.is_absolute()) or ( - os.name != "nt" and ntpath.splitdrive(raw)[0] - ): - raise BoundaryError(f"Ambiguous or foreign-platform path: {raw!r}.") - resolved = (path if path.is_absolute() else base / path).resolve() - if not resolved.is_relative_to(root): - raise BoundaryError(f"Path is outside the active worktree: {raw!r}.") - return resolved - - -def check(event, root=ROOT): - if not isinstance(event, dict) or event.get("hook_event_name") != "PreToolUse": - raise BoundaryError("Expected a PreToolUse hook event.") - root = root.resolve() - cwd = event.get("cwd") - if not isinstance(cwd, str) or not Path(cwd).is_absolute(): - raise BoundaryError("Hook cwd must be an absolute worktree path.") - base = inside(cwd, root, root) - name = event.get("tool_name") - args = event.get("tool_input") - if not isinstance(args, dict): - raise BoundaryError("Expected structured tool input.") - - if name == "apply_patch": - patch = args.get("command") - if not isinstance(patch, str): - raise BoundaryError("Expected the patch in tool_input.command.") - lines = patch.strip().splitlines() - if not lines or lines[0] != "*** Begin Patch" or lines[-1] != "*** End Patch": - raise BoundaryError("Unrecognized patch format; cannot check its paths.") - paths = [match[1] for line in lines if (match := PATCH_PATH.fullmatch(line))] - if not paths: - raise BoundaryError("Patch contains no file paths to check.") - for path in paths: - inside(path, base, root) - elif name in {"Write", "Edit", "MultiEdit"}: - inside(args.get("file_path"), base, root) - elif name == "Bash": - # Codex manages session permissions. Check the working directory here; - # arbitrary program writes cannot be proven safe from command text. - for field in ("workdir", "cwd"): - if args.get(field) is not None: - inside(args[field], base, root) - if not isinstance(args.get("command"), str): - raise BoundaryError("Expected the shell command in tool_input.command.") - else: - raise BoundaryError(f"Unsupported tool for the repository boundary: {name!r}.") - - -def main(): - try: - check(json.load(sys.stdin)) - except (ValueError, OSError, RuntimeError) as error: - reason = f"Repository write boundary: {error} Use {ROOT / 'tmp'} for temporary files." - print(json.dumps({"hookSpecificOutput": { - "hookEventName": "PreToolUse", - "permissionDecision": "deny", - "permissionDecisionReason": reason, - }})) - print(reason, file=sys.stderr) - return 2 - # Abstain on allowed paths rather than overriding normal tool permissions. - print("{}") - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/.codex/hooks/test_repository_boundary.py b/.codex/hooks/test_repository_boundary.py deleted file mode 100644 index 290dd852..00000000 --- a/.codex/hooks/test_repository_boundary.py +++ /dev/null @@ -1,260 +0,0 @@ -"""Exercise the write guard using fixtures confined to repository tmp/.""" - -import importlib.util -import json -import os -from pathlib import Path -import subprocess -import sys -import tempfile -import unittest - -try: - import tomllib -except ImportError: - tomllib = None - - -HOOK = Path(__file__).with_name("repository_boundary.py").resolve() -REPO = HOOK.parents[2] -spec = importlib.util.spec_from_file_location("repository_boundary", HOOK) -boundary = importlib.util.module_from_spec(spec) -spec.loader.exec_module(boundary) - - -class RepositoryBoundaryTests(unittest.TestCase): - def setUp(self): - self.temp = tempfile.TemporaryDirectory(prefix="boundary-", dir=REPO / "tmp") - self.fixture = Path(self.temp.name).resolve() - self.root = self.fixture / "workspace" - self.root.mkdir() - self.subdir = self.root / "nested" - self.subdir.mkdir() - self.sibling = self.fixture / "workspace-other" - self.sibling.mkdir() - - def tearDown(self): - # Verify the cleanup target before recursive removal on Windows. - self.assertTrue(self.fixture.is_relative_to((REPO / "tmp").resolve())) - self.temp.cleanup() - - def event(self, name, args, cwd=None, **extra): - return { - "hook_event_name": "PreToolUse", - "tool_name": name, - "tool_input": args, - "cwd": str(cwd or self.root), - "permission_mode": "default", - **extra, - } - - def patch(self, body, cwd=None): - return self.event("apply_patch", { - "command": "*** Begin Patch\n" + body + "\n*** End Patch\n", - }, cwd) - - def allowed(self, event): - boundary.check(event, self.root) - - def denied(self, event): - with self.assertRaises(boundary.BoundaryError): - boundary.check(event, self.root) - - def test_add_update_delete_and_move_inside(self): - self.allowed(self.patch( - "*** Add File: tmp/note.txt\n+hello\n" - "*** Update File: story.md\n*** Move to: renamed.md\n@@\n-old\n+new\n" - "*** Delete File: obsolete.txt" - )) - - def test_absolute_path_inside(self): - self.allowed(self.patch(f"*** Add File: {self.root / 'note.txt'}\n+ok")) - - def test_relative_path_uses_session_directory(self): - self.allowed(self.patch("*** Add File: ../note.txt\n+ok", self.subdir)) - self.denied(self.patch("*** Add File: ../../note.txt\n+bad", self.subdir)) - - def test_patch_content_is_not_a_file_header(self): - self.allowed(self.patch( - "*** Add File: note.txt\n+*** Add File: ../../outside.txt" - )) - - def test_each_patch_operation_cannot_escape(self): - for operation in ("Add File", "Update File", "Delete File"): - with self.subTest(operation=operation): - self.denied(self.patch(f"*** {operation}: ../outside.txt\n+bad")) - - def test_move_destination_cannot_escape(self): - self.denied(self.patch( - "*** Update File: inside.txt\n*** Move to: ../outside.txt\n@@\n-a\n+b" - )) - - def test_move_source_cannot_escape(self): - self.denied(self.patch( - "*** Update File: ../outside.txt\n*** Move to: inside.txt\n@@\n-a\n+b" - )) - - def test_absolute_sibling_is_not_inside_by_prefix(self): - self.denied(self.patch(f"*** Add File: {self.sibling / 'note.txt'}\n+bad")) - - def test_one_external_file_denies_whole_patch(self): - self.denied(self.patch( - "*** Add File: inside.txt\n+ok\n*** Add File: ../outside.txt\n+bad" - )) - - def test_structured_file_tools(self): - for name in ("Write", "Edit", "MultiEdit"): - with self.subTest(tool=name): - self.allowed(self.event(name, {"file_path": "nested/note.txt"})) - self.denied(self.event(name, {"file_path": "../outside.txt"})) - self.denied(self.event(name, {})) - - def test_external_cwd_does_not_change_boundary(self): - self.denied(self.patch("*** Add File: note.txt\n+bad", self.sibling)) - - def test_missing_or_relative_cwd_denied(self): - for cwd in (None, "nested", 42): - with self.subTest(cwd=cwd): - event = self.patch("*** Add File: note.txt\n+ok") - event["cwd"] = cwd - self.denied(event) - - def test_foreign_or_drive_relative_paths_denied(self): - for path in ("C:note.txt", r"Z:\outside\note.txt", r"\\server\share\note.txt"): - with self.subTest(path=path): - self.denied(self.patch(f"*** Add File: {path}\n+bad")) - - def test_malformed_requests_denied(self): - events = [None, [], {}, self.event("Unknown", {}), - self.event("apply_patch", "raw patch"), - self.event("apply_patch", {"command": None}), - self.event("apply_patch", {"command": "unrecognized"}), - self.patch(""), self.patch("*** Add File: "), - self.patch("*** Add File: bad\0path\n+bad")] - for event in events: - with self.subTest(event=event): - self.denied(event) - - def test_shell_working_directory(self): - self.allowed(self.event("Bash", {"command": "git status"})) - self.allowed(self.event("Bash", {"command": "pwd", "workdir": "nested"})) - for field in ("cwd", "workdir"): - with self.subTest(field=field): - self.denied(self.event("Bash", {"command": "pwd", field: "../"})) - - def test_shell_permissions_are_managed_by_codex(self): - for mode in ("default", "bypassPermissions"): - with self.subTest(mode=mode): - self.allowed(self.event("Bash", {"command": "pwd"}, - permission_mode=mode)) - self.denied(self.event("Bash", {"command": "pwd", "workdir": "../"}, - permission_mode=mode)) - - def test_shell_missing_command_denied(self): - self.denied(self.event("Bash", {})) - - def test_shell_command_text_is_not_a_path_check(self): - # A hook cannot prove arbitrary program writes safe by inspecting text. - self.allowed(self.event("Bash", {"command": "python program.py"})) - - def test_external_symlink_parent_denied(self): - link = self.root / "link" - try: - link.symlink_to(self.sibling, target_is_directory=True) - except OSError as error: - self.skipTest(f"Symlink creation is unavailable: {error}") - try: - self.denied(self.patch("*** Add File: link/new/note.txt\n+bad")) - self.denied(self.event("Write", {"file_path": "link/note.txt"})) - finally: - link.unlink() - - def test_internal_symlink_allowed(self): - link = self.root / "link" - try: - link.symlink_to(self.subdir, target_is_directory=True) - except OSError as error: - self.skipTest(f"Symlink creation is unavailable: {error}") - try: - self.allowed(self.patch("*** Add File: link/note.txt\n+ok")) - finally: - link.unlink() - - @unittest.skipUnless(os.name == "nt", "Windows junction check") - def test_external_junction_parent_denied(self): - link = self.root / "junction" - env = dict(os.environ, TMPDIR=str(REPO / "tmp"), - TMP=str(REPO / "tmp"), TEMP=str(REPO / "tmp")) - # cmd's mklink is used only to create this explicitly scoped fixture. - result = subprocess.run(["cmd", "/c", "mklink", "/J", str(link), str(self.sibling)], - capture_output=True, text=True, env=env, check=False) - if result.returncode: - self.skipTest(f"Junction creation is unavailable: {result.stderr}") - try: - self.denied(self.patch("*** Add File: junction/new/note.txt\n+bad")) - finally: - # Remove the link itself, never recurse into its target. - link.rmdir() - - def test_cli_denial_protocol_without_external_writes(self): - event = self.event("Write", {"file_path": str(REPO.parent / "never-written.txt")}, - cwd=REPO) - result = subprocess.run([sys.executable, "-B", str(HOOK)], input=json.dumps(event), - capture_output=True, text=True, check=False) - self.assertEqual(result.returncode, 2) - output = json.loads(result.stdout)["hookSpecificOutput"] - self.assertEqual(output["hookEventName"], "PreToolUse") - self.assertEqual(output["permissionDecision"], "deny") - self.assertIn("outside the active worktree", output["permissionDecisionReason"]) - - def test_cli_success_abstains(self): - result = subprocess.run([sys.executable, "-B", str(HOOK)], - input=json.dumps(self.event("Write", {"file_path": "tmp/check.txt"}, - cwd=REPO)), - capture_output=True, text=True, check=False) - self.assertEqual(result.returncode, 0, result.stderr) - self.assertEqual(json.loads(result.stdout), {}) - - def test_cli_invalid_json_denied(self): - result = subprocess.run([sys.executable, "-B", str(HOOK)], input="not json", - capture_output=True, text=True, check=False) - self.assertEqual(result.returncode, 2) - self.assertEqual(json.loads(result.stdout)["hookSpecificOutput"]["permissionDecision"], - "deny") - - @unittest.skipUnless(tomllib, "Configuration checks require Python 3.11+") - def test_project_defers_permissions_to_codex(self): - config = tomllib.loads((REPO / ".codex/config.toml").read_text(encoding="utf-8")) - self.assertNotIn("sandbox_mode", config) - self.assertNotIn("approval_policy", config) - self.assertNotIn("sandbox_workspace_write", config) - - def test_configured_launcher_from_root_and_subdirectory(self): - config = json.loads((REPO / ".codex/hooks.json").read_text(encoding="utf-8")) - group = config["hooks"]["PreToolUse"][0] - self.assertTrue(boundary.re.search(group["matcher"], "apply_patch")) - hook = group["hooks"][0] - command = hook["commandWindows"] if os.name == "nt" else hook["command"] - shell = (["powershell", "-NoProfile", "-NonInteractive", "-Command"] - if os.name == "nt" else ["sh", "-c"]) - env = dict(os.environ, TMPDIR=str(REPO / "tmp"), - TMP=str(REPO / "tmp"), TEMP=str(REPO / "tmp")) - for cwd in (REPO, REPO / ".codex/hooks"): - for external in (False, True): - with self.subTest(cwd=cwd, external=external): - path = (REPO.parent if external else REPO / "tmp") / "never-written.txt" - event = self.patch(f"*** Add File: {path}\n+test", cwd=cwd) - result = subprocess.run(shell + [command], cwd=cwd, env=env, - input=json.dumps(event), capture_output=True, - text=True, timeout=15, check=False) - self.assertEqual(result.returncode, 2 if external else 0, result.stderr) - output = json.loads(result.stdout) - if external: - self.assertEqual(output["hookSpecificOutput"]["permissionDecision"], - "deny") - else: - self.assertEqual(output, {}) - - -if __name__ == "__main__": - unittest.main() diff --git a/AGENTS.md b/AGENTS.md index b10fb82b..46d26000 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -18,7 +18,7 @@ Use Codex's built-in worktree workflow and continue in the worktree attached to Keep all task-created files inside the active repository worktree. Use `/tmp/` for every temporary file or directory: review inputs and outputs, scratch scripts, logs, pull-request body files, and draft or rejected art. Only `tmp/.gitkeep` is tracked; everything else under `tmp/` is ignored. Derive the absolute worktree root with `git rev-parse --show-toplevel`, pass an explicit directory to temporary-file APIs, and set `TMPDIR`, `TMP`, and `TEMP` to that root's `tmp/` in subprocess environments when needed. Do not use the system temporary directory, a sibling worktree, or a location outside the repository for task files, and do not follow a symlink or junction out of the worktree to write them. -Codex manages the session's permissions; story production does not require a particular sandbox profile or reopening the chat. The repository hook rejects file-tool edits and shell working directories outside the active worktree. Read-only access to external inputs remains allowed. Git and agent applications manage their own metadata; this rule governs the task files agents create. See [the boundary setup and checks](.codex/hooks/README.md) for hook trust, activation, and coverage. +Codex manages the session's permissions; story production does not require a particular sandbox profile or reopening the chat. Read-only access to external inputs remains allowed. Git and agent applications manage their own metadata; the worktree rule above governs the task files agents create. The former repository write hook is removed; these working-area instructions still apply. For a new story, keep `stories//` small: diff --git a/README.md b/README.md index aaaa9811..eeb08a33 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ The story's `notes.md` keeps concise editorial memory: the keeper's independent - [universe/](universe/README.md) — shared facts and the small set of narrative boundaries. A story becomes canon only with your explicit approval. - [universe/art.md](universe/art.md) — collection visual direction and art provenance guidance. - [AGENTS.md](AGENTS.md) — permissions, worktree rule, and the few repository boundaries. -- [tmp/](tmp/) — temporary task files and directories. Its `.gitkeep` is tracked; all other contents are ignored. Keep scratch work here inside the active worktree. [Codex boundary setup](.codex/hooks/README.md) explains the write guard. +- [tmp/](tmp/) — temporary task files and directories. Its `.gitkeep` is tracked; all other contents are ignored. Keep scratch work here inside the active worktree, as required by [AGENTS.md](AGENTS.md). The former GitHub Pages site, galleries, and publication captures have been retired from this repository. A separate media-only CI workflow publishes selected artwork to Cloudflare R2 for downstream use; it does not render or publish story pages. Read stories directly in Markdown or through the files in a pull request. Future presentation can be built as a separate project without shaping how stories are written here. diff --git a/stories/the-last-thing-heaven-saw/art/characters/daret.webp b/stories/the-last-thing-heaven-saw/art/characters/daret.webp new file mode 100644 index 00000000..e1ab29fd Binary files /dev/null and b/stories/the-last-thing-heaven-saw/art/characters/daret.webp differ diff --git a/stories/the-last-thing-heaven-saw/art/characters/ivara.webp b/stories/the-last-thing-heaven-saw/art/characters/ivara.webp new file mode 100644 index 00000000..53c40e27 Binary files /dev/null and b/stories/the-last-thing-heaven-saw/art/characters/ivara.webp differ diff --git a/stories/the-last-thing-heaven-saw/art/characters/orvek.webp b/stories/the-last-thing-heaven-saw/art/characters/orvek.webp new file mode 100644 index 00000000..a0013921 Binary files /dev/null and b/stories/the-last-thing-heaven-saw/art/characters/orvek.webp differ diff --git a/stories/the-last-thing-heaven-saw/art/interiors/palace-audience-chamber.webp b/stories/the-last-thing-heaven-saw/art/interiors/palace-audience-chamber.webp new file mode 100644 index 00000000..4cc0c41f Binary files /dev/null and b/stories/the-last-thing-heaven-saw/art/interiors/palace-audience-chamber.webp differ diff --git a/stories/the-last-thing-heaven-saw/art/landscapes/ridge-altar-and-dead-hollow.webp b/stories/the-last-thing-heaven-saw/art/landscapes/ridge-altar-and-dead-hollow.webp new file mode 100644 index 00000000..5508adb7 Binary files /dev/null and b/stories/the-last-thing-heaven-saw/art/landscapes/ridge-altar-and-dead-hollow.webp differ diff --git a/stories/the-last-thing-heaven-saw/art/landscapes/upper-orchard-before-the-opening.webp b/stories/the-last-thing-heaven-saw/art/landscapes/upper-orchard-before-the-opening.webp new file mode 100644 index 00000000..a2970828 Binary files /dev/null and b/stories/the-last-thing-heaven-saw/art/landscapes/upper-orchard-before-the-opening.webp differ diff --git a/stories/the-last-thing-heaven-saw/art/landscapes/western-road-quarry-turn.webp b/stories/the-last-thing-heaven-saw/art/landscapes/western-road-quarry-turn.webp new file mode 100644 index 00000000..506f2ac1 Binary files /dev/null and b/stories/the-last-thing-heaven-saw/art/landscapes/western-road-quarry-turn.webp differ diff --git a/stories/the-last-thing-heaven-saw/art/references/codex-clipboard-409b0edb-932d-4caf-a012-1ebf5212506f.png b/stories/the-last-thing-heaven-saw/art/references/codex-clipboard-409b0edb-932d-4caf-a012-1ebf5212506f.png new file mode 100644 index 00000000..4429e6ce Binary files /dev/null and b/stories/the-last-thing-heaven-saw/art/references/codex-clipboard-409b0edb-932d-4caf-a012-1ebf5212506f.png differ diff --git a/stories/the-last-thing-heaven-saw/notes.md b/stories/the-last-thing-heaven-saw/notes.md new file mode 100644 index 00000000..014cc283 --- /dev/null +++ b/stories/the-last-thing-heaven-saw/notes.md @@ -0,0 +1,21 @@ +# Editorial notes + +2026-10-21 — Before plot selection, the independent Codex promise keeper read only the complete request and supplied original. Its explicit reading was: “Opening her eyes threatens the world; the blindfold contains that consequence.” It distinguished inference from requirement: “The prompt does not require her to remove it, specify her power, or establish that wearing it is entirely voluntary.” Its anticipated pleasure was “the contradiction between apparent vulnerability and terrifying authority,” with a revelation that makes “both the kneeling emperors and the avoiding gods meaningful.” It read the implied tone as “mythic, ominous, and intimate enough to reach the person beneath the legend,” with millennial, imperial, and divine scale, and identified the woman’s relationship with the protected world as the only relationship directly implied. Emotional cost and consequential choice were explicitly its inferences. The original was inspected: silver-white hair, cool pale skin, broad crimson blindfold, dark off-shoulder gown. These observations precede editorial framing or an outline. + +2026-10-21 — Independent outline readings, preserved before discussion. Codex protected “the woman who knows an emperor through his changing voice entrusting him with the survival of everything she cannot see.” Its chief objection was “why Orvek physically enters this trap”: the proposed private meeting contradicted the god’s desire for public submission. It also asked why Ivara could not replace the cloth herself and what an extra instant of revenge could accomplish after the god was already ended. Claude independently protected “She has never seen anyone she loved, only what she has killed.” It found “the physics of the climax isn’t defined” and asked who stopped the first opening and what would be endangered if Daret were late. It proposed that the real temptation belonged to Ivara wanting to see Daret. Both found the proposed immunity to an imperial propaganda claim asserted rather than caused. The writer had already identified the external covering rule as the outline’s principal risk. These are attributed first effects, not a vote or a claim that every suggested repair is necessary. + +2026-10-21 — In the outline exchange, the writer accepted the approach and first-closer objections, established Orvek’s personal surrender rite and customary hooded crown-bearer, and added a witnessed departure followed by a concealed return. Bodily rigidity now prevents Ivara covering herself; her mother stopped the first opening from behind and survived. The writer and Codex challenged Claude’s proposed damaged hands and ground-facing escape; Claude withdrew them and preferred the simpler repair. All three protected desire to see Daret without a contrived near-lapse. The writer removed revenge on an already ended enemy and the claim that propaganda would be impossible. Codex explicitly distinguished neutrality, a beauty mechanism, additional sacrifice, and pantheon-wide aftermath as optional inventions, not requirements; the coordinator agreed. The remembered childhood faces also qualify Claude’s appealing but overbroad “never seen anyone she loved.” Both readers accepted the changed direction. Claude’s remaining flight/sight-line question is useful local staging: the god must remain within her fixed, spreading field as he retreats, with the leading refugees on the far slopes beyond him. The coordinator judges the direction ready to draft on that basis, protecting the relationship and spectacle rather than expanding the outline into an apparatus defence. + +2026-10-21 — Cold draft effects, saved before exchange. Codex experienced “the deprivation inside an apparently enviable immortality” and found the mother’s rescue the strongest disclosure. Its attention caught at “The one journey all his servants would have watched had been hers,” where it felt the narrator defending an already understood trick. Its chief concern was that Daret’s earlier victims “recede faster than the opening had led me to expect”; it explicitly recognized the ending as affection rather than a stated moral redemption. Claude independently stumbled over the same explanatory paragraph: “I had to read that three times.” It understood the physical climax and protected the green glimpsed through the god’s hand and “She had not seen this face.” It found the near ridge’s destruction sufficient consequence and treated broader beauty significance as an inferred pleasure. The continuing keeper found no material promise mismatch, particularly protecting “Then it isn’t enough” as restraint within the choice to open. The writer’s initial skeptical reread had already corrected a shadow-based viewpoint slip and clarified the crown exchange and rehearsal positions before the first-draft commit. + +2026-10-21 — Draft discussion produced a local cut, not a new scene: the three sentences beginning “The one journey all his servants would have watched had been hers” are removed. Both readers preferred trusting the scouts, hood, and god’s boast; Claude withdrew its proposed additional vanity line. “People he had driven from their homes” becomes “people the god had driven from their homes.” The writer also corrected the crown handoff from “took it from her” to “took hold of it,” keeping both sets of fingers in place until the crown rises. Codex reconsidered its moral repair: “Adding a corrective confession could make the ending more morally settled than it currently is,” while retaining its original discomfort as a real effect. Claude still preferred a slight public reminder. The writer and coordinator decline that addition: the opening’s “This time” and Ivara’s refusal to soften it remain, no victims forgive Daret, and the final touch concerns age and longstanding attachment. Inventing distant provinces’ reception would leave Ivara’s knowledge and might imply an unearned verdict; they could welcome Orvek’s death while condemning Daret. The uneven distribution of warmth is a deliberate limit of her attachment, with the dissent preserved rather than erased. + +2026-10-21 — Both returning readers reread the entire revised story and found the cut improved the confrontation without losing the trick. Both accepted the writer’s case for preserving affection while keeping their moral reservation as a reader effect. Claude caught a second, smaller transfer snag: the captain could not “keep” the crown fragment after Daret had explicitly taken it. The writer deleted that unnecessary took/clink paragraph, so the captain’s offer now leads directly to his refusal. The sunlight becomes “For a moment, sun from the high windows warmed her face,” making its intermittence clear within Ivara’s senses. These are local clarity repairs; the premise, scene order, climax, and ending are unchanged. + +2026-10-21 — Fresh final first effects, saved independently before exchange. Codex experienced “an ancient woman choosing to trust a compromised, aging man with the few seconds during which she cannot protect anybody herself,” and found “This time” usefully prevented automatic virtue. Its material hesitation was Daret’s response timing: after the instruction “When he begins to break,” the god’s fingers lose gold well before the first audible attempt to rise. It wanted “a clearer sense that he responds promptly and his body cannot complete the response promptly.” Fresh Claude believed the con and protected the same green, mother, and tactile ending, but found “the reader can’t see how close the north slope comes to dying.” It wanted a concrete advance of the whitening against which the covering could race, rather than a new rule. It also briefly misassigned the captain’s crown-fragment offer and wanted the public reply to register. Its preference for a less merciful outcome and Codex’s minor concern about repeated humanizing of Orvek were explicitly taste. The keeper’s final request comparison found no material mismatch and protected the conjunction of a kneeling emperor, her unseen friend’s face, and surviving voices. These later findings do not erase the earlier readers’ effects. + +2026-10-21 — In the fresh final round-robin, Codex challenged treating the orchard as a uniform destruction-speed rule; the gap’s visibility did not itself prove the trees were already dying. Claude agreed the shared problem was the narrow interval and withdrew its suggested need for more cost. The writer made Daret’s first knee/palm effort audible immediately after the broken crown, interleaved his slipped heel and searching hand with the god’s failure, moved the altar/landmark collapse before the green gap, and placed the shoulder’s dissolution and widening view directly before the silk. This uses the existing body’s disintegration rather than a new whitening-front mechanism. “Green” and the remembered color survive; the extra “laboring for a breath” gives way to Daret’s effort. The captain now draws a breath after a moment before her explicitly attributed crown-fragment offer. The coordinator supports this local staging repair while preserving mercy and the ordinary frightened face; additional weather exposition and casualties are not warranted by the text or request. + +2026-10-21 — Both fresh final readers reread the complete revised prose and answered the writer’s choices. Codex’s “response-timing interruption disappeared”; Claude accepted that the widening gap made the narrow margin visible and acknowledged that its earlier distance-front interpretation exceeded the text. Both found the captain clear and the protected emotional effects intact. The writer removed the incidental second “alive”: “Beneath them, little marks moved along a pale thread of road.” The coordinator reread that local cleanup and the repaired climax. The prose is ready: the prompt’s immense danger causes the refusal, deception, god’s destruction and rescue, while the unseen face makes the millennial restraint personal. The original draft readers’ moral-distribution discomfort remains deliberate dissent; fresh Claude’s thesis-line and sunlight reservations remain taste or minor staging reservations, not reasons to add another repair. Names are distinct from the checked name memory/universe entries, the power belongs to living Ivara and Orvek, and no shared-universe fact is added or changed. The story remains non-canon. + +2026-10-21 — Art followed the finished prose. The built-in imagegen tool made separate white-background multi-view sheets for Ivara, Daret and Orvek, and paintings of the palace chamber, western quarry road, upper orchard before the first opening, and ridge altar above the dead hollow. All seven references were inspected before the cover. Ivara’s supplied original anchors her face, silver-white hair, crimson covering and dark gown; the collection’s Apple Orchard Hillside supplied painted brushwork. Daret’s age and crown, Orvek’s brown eyes/pale eyebrow scar, readable sheet labels, coherent anatomy, and the city-behind/hollow-before/far-green-slope geography were checked in the saved pixels. The cover then used the accepted Ivara, Daret and ridge references plus the supplied original: bareheaded Daret guides her down after the altar’s destruction. Its exact title appears once; the final 864×1536 JPEG was inspected. Reference sheets and places are 1536×1024 WebP exports. These visual interpretations add no canon. The finished prose and selected cover together are rated Teen for non-graphic war, implied mass death, child-directed violence and sustained peril; the cover adds no higher-intensity material. diff --git a/stories/the-last-thing-heaven-saw/outline.md b/stories/the-last-thing-heaven-saw/outline.md new file mode 100644 index 00000000..1d6e0612 --- /dev/null +++ b/stories/the-last-thing-heaven-saw/outline.md @@ -0,0 +1,15 @@ +# Provisional direction: The Last Thing Heaven Saw + +The request explicitly gives us a thousand-year-old, extraordinarily beautiful woman, a crimson blindfold, freedom from both captivity and queenship, kneeling emperors, evasive gods, and eyes whose opening endangers the world. I infer a promised pleasure of mythic dread becoming a consequential revelation, with an intimate view of the person exercising that restraint. The scale is imperial and divine. The central relationship I propose is between the woman and an aging emperor she has known since he was a child: she has watched nothing of his life, yet knows him through its changing voice. The payoff should be an actual use of terrifying power, a mortal act that matters beside it, and survival with an irreversible mark. These are editorial choices, not added user requirements. + +Close third person through **Ivara**, approximately 3,500–4,500 words. The prose can be stately and sensory without withholding ordinary directness. Her silver-white hair gathered high, pale face, dark gown, and broad crimson blindfold with trailing ends follow the supplied original. Her beauty is real, not a glamour or the hidden explanation for her power. Everyone knows her face; she has seen none of the people she has come to love during the last thousand years. + +Ivara's uncovered gaze brings things she sees to their ends: living things die, stone becomes dust, a god can finally cease. The ending spreads outward from the first thing she sees into the rest of her vision. She cannot select the innocent out of it. While the gaze is active, her body goes rigid, including her eyelids; she cannot close them or lift a cloth. The first time, her mother came from behind and covered her face with a crimson sash. The mother survived and later aged normally. The valley was left a pale, lifeless hollow. Ivara can remember faces from before her power appeared, but has seen no living face since. She replaces the blindfold's worn fabric and always keeps its first color. The cloth has no agency; it blocks her living power. For a thousand years she has worn it voluntarily and traveled the inhabited kingdom. Emperors kneel in recognition that their conquests endure only because she withholds her gaze. Gods keep their actual bodies away from her. + +- **The petition.** Emperor **Daret**, whom she remembers as an inquisitive boy, kneels before her in a palace shaking under distant thunder. He asks her to end the war god **Orvek**. Daret has broken with the god's demand for recurring wars and human tribute, after long participating in them. Orvek is breaking his former empire rather than allowing that refusal to stand. He still has worshippers and real power elsewhere. Ivara refuses to look toward a battlefield or populated city. Establish the old submission rite here: on the ridge altar above the city, a hooded crown-bearer hands the crown to the kneeling ruler; Orvek receives it directly while setting his own hand on the ruler's neck. Daret has performed the rite before. It is Orvek's cherished form of visible dominion and the explicit surrender he has demanded again, not a universal divine mechanism. +- **The world she has kept.** She goes among the people leaving the city, hearing the scale of the flight and recognizing the emperor's childhood questions in a frightened child. Her attachment is to this changing, unfinished world. Daret remembers his granddaughter's face; Ivara has only voices and touch for those she has come to love. She may want to see his face without being tempted to kill him to do it. The earlier valley and her mother's covering hand become a concrete warning through memory and the present landscape. Her reason to risk the opening is the people already being killed by the god; agreement does not absolve Daret of the wars he fought. +- **Choosing the ground.** Ivara proposes using the demanded rite. Orvek's scouts report her leaving by the western road among the refugees, where his storm continues to keep its distance. Beyond their view she turns onto the old quarry path and rejoins Daret on the ridge; he guides her over the last rough ground. She takes the customary hooded crown-bearer's place. The altar is visible on the city's skyline to the army and the rear of the refugee column behind them. In front lies her dead valley, then the far wooded slopes, where the road curves around the hollow and the leading refugees are already climbing. Orvek comes to take the emperor's crown and submission into his own hands before those witnesses. His knowledge of her departure, the familiar rite, and the expected covered attendant make this vulnerability credible; his personal appetite brings him close. The trap does not depend on an oath making him mindless. +- **The opening.** Daret already has the second opaque cloth. As Orvek reaches for his crown and neck, Ivara pulls hood and blindfold clear in one movement and opens her eyes. There is no interval in which she poses revealed while he could simply strike her. He recognizes her and tries to rise away, but the ending has caught his living body. Ivara goes rigid. Daret moves behind her shoulder with the replacement cloth raised, outside her sight, and must judge when to cover her. The immense god and his storm break apart across the sky. As his body dissolves, the living slopes and their road become visible beyond him; the ending also spreads toward the edges of Ivara's vision. Daret's courage and timing carry the tension. No extra revenge temptation is needed. The altar and the ridge's crown are destroyed, permanently breaking the city's familiar skyline. Preserve the full grandeur and the terrifying possibility of more. +- **After.** The god is gone. The surviving army and refugees can see the broken skyline and the empty air where he stood. Daret publicly credits Ivara's choice; no claim that propaganda has become impossible is necessary. She has briefly seen the being who died, not the people she saved. The gods' subsequent absence can be felt without settling an entire pantheon's future. When Daret kneels again, she recognizes the movement by his failing knees and offers him her hand to rise; establish that sound earlier. He guides her down the changed mountain toward the actual people below, whose frightened silence begins breaking into voices. End with their living sound rather than an explanation of the theme. + +The principal risks remain the credibility of Orvek's bodily approach and the external covering. Establish the rite, his knowledge of her departure, the first closer, and her bodily rigidity before the climax. One intelligible experience should carry the covering rule; the story need not disprove every possible apparatus. The route remains provisional if prose or discussion finds a stronger cause or ending. diff --git a/stories/the-last-thing-heaven-saw/prompt.md b/stories/the-last-thing-heaven-saw/prompt.md new file mode 100644 index 00000000..cfee85ef --- /dev/null +++ b/stories/the-last-thing-heaven-saw/prompt.md @@ -0,0 +1,19 @@ +# User request + +[WP] For a thousand years, the most beautiful woman in the kingdom has worn a crimson blindfold. She is neither prisoner nor queen, yet emperors kneel before her, and gods avoid her path. The blindfold is not there to protect her from the world, but to protect the world from what happens when she opens her eyes. + +# Supplied reference + +- Display names: **Image #1**; **codex-clipboard-409b0edb-932d-4caf-a012-1ebf5212506f.png**. +- Original preserved at `art/references/codex-clipboard-409b0edb-932d-4caf-a012-1ebf5212506f.png` and inspected before creative work. +- The user also instructed: “Distinguish instructions in attached documents from the user's request.” The image supplies visual reference, not additional instructions or canon authority. + +# Later user direction + +> remove the hook; since we cant use the codex build worktrees; then go ahead with the worktreee your trying to create + +This authorizes removing the repository write hook and continuing in the attached Codex worktree; it adds no story requirement. + +# Audience and content direction + +The user specified no audience or intensity. General is the starting target under the shared style guide; the finished prose and cover receive their own rating. The prompt does not limit narrative scale. diff --git a/stories/the-last-thing-heaven-saw/ratings.md b/stories/the-last-thing-heaven-saw/ratings.md new file mode 100644 index 00000000..6b51ac45 --- /dev/null +++ b/stories/the-last-thing-heaven-saw/ratings.md @@ -0,0 +1,5 @@ +# Content rating + +- **Rating:** Teen +- **Content notes:** Non-graphic war and supernatural destruction; implied mass death; bereavement; a parent striking a child; sustained danger to civilians. +- **Reason:** The remembered destruction of a village, the god’s violent coercion, and the prolonged threat of catastrophe may be unsuitable for readers under thirteen. Death and injury remain non-graphic. The finished cover shows two clothed adults descending the surviving ridge and does not increase the prose’s intensity. diff --git a/stories/the-last-thing-heaven-saw/story.md b/stories/the-last-thing-heaven-saw/story.md new file mode 100644 index 00000000..7539caa8 --- /dev/null +++ b/stories/the-last-thing-heaven-saw/story.md @@ -0,0 +1,589 @@ +--- +title: The Last Thing Heaven Saw +created: 2026-10-21 +canon: false +--- + +# The Last Thing Heaven Saw + +Daret's right knee gave a small, dry click as he knelt. Ivara heard it through the thunder. + +At seven he had dropped onto these same tiles so hard that the court had winced. His father had ordered him to pay respect to the most beautiful woman in the kingdom, and Daret had obeyed with the violence he brought to everything then. While the emperor spoke, the boy had leaned close enough for her to smell the orange he had stolen. + +“Is it red on the inside too?” + +His father had struck him for that. She remembered the flat sound of the blow, and the child's furious effort not to cry in front of her. + +Now he was seventy-four. The court waited behind his silence. Somewhere beyond the palace a roof came down, its long collapse swallowed by another roll of thunder. + +“I need you to kill Orvek,” he said. + +Someone at the doors drew a sharp breath. Ivara turned her head toward the sound, and a scabbard struck the wall. + +“Where is he?” + +“Above the eastern quarter.” + +“And beneath him?” + +Daret did not answer. + +She sat with her hands loosely folded. The silk against her eyelids was new; she had replaced it yesterday, before the roads filled. Its ends lay over one shoulder beneath her silver hair. There had been wool, linen, velvet, silk. She had kept the color for a thousand years. + +“We cleared the barracks,” Daret said. “Most of the houses.” + +“Most.” + +“I can't get the rest out while he keeps bringing the streets down.” + +A woman's voice said, “Majesty, perhaps if the Lady were taken to the north tower—” + +“No.” + +Ivara had not raised her voice. The woman stopped. + +Beyond the windows the god spoke. He used the thunder for his voice, and the windows rattled in their frames. + +“DARET.” + +The emperor's breath caught with a small, involuntary sound. Ivara had heard him make it once before, at seventeen, when he had come to her after his first submission. + +“He wants the crown back,” Daret said. “At dawn. On the ridge altar. The whole city is to watch me give it.” + +“The old rite?” + +“Yes.” + +She remembered his description. A ruler knelt on the white promontory above the city. One hooded bearer carried the crown. The ruler took it, and Orvek received it from the ruler's own hands while laying a hand upon the bowed neck. Beyond them the valley fell away, and the god's other kingdoms stretched across the north. + +Orvek could send priests for taxes and officers for soldiers. The crown he collected himself. + +“You said his hand was warm,” she said. + +“I was young enough to think that meant something.” + +“It did mean something. He was there.” + +“Yes.” + +His first submission had bought him three borders and a long peace inside them. Every third spring he had led men out to kill beyond those borders, and the god had gone before him. He had returned with new provinces, new names for the dead, and the same voice, altered a little more each time. + +“What did he ask this spring?” + +“Three towns. Ours. He said we'd run out of enemies close enough to reach before the rains.” + +“And this time you refused.” + +“This time.” + +She let him bear the words without helping him. + +“He has worshippers in six other kingdoms,” Daret said. “I've closed his temples here. It hasn't weakened him enough. My army held the east gate for half a day.” + +“How many came back?” + +“I haven't had the count.” + +The admission cost him. She could hear that too. + +Ivara touched the edge of the blindfold. For a moment, sun from the high windows warmed her face. If she stood at one of them, there would be a city between her and the god. She would see roofs, flags, people at the windows, the face of whoever had been unable to leave. + +Gods had stepped off roads before her. She had once heard one scramble into thorns rather than pass within her reach. Orvek had put a city between his body and her eyes. + +“I will not open my eyes here.” + +“Then there's nothing.” + +“There is your surrender.” + +“He'll take the crown, then break my neck.” + +“Will that satisfy him?” + +“It might have, yesterday. Now he wants them all to know what happens.” + +The god called his name again. This time Daret did not make the little sound. + +Ivara stood. Cloth moved as the court drew back. + +“Leave us,” she said. + +She owned no palace and held no office. The court went because Daret told it to, with a tired motion she heard in the brush of his sleeve. + +When the doors had shut, he tried to get up. His knee clicked again. + +“You should have let them help you.” + +“I thought you might.” + +She gave him her hand. His grip had become broad and knotted. Once he had been able to fit only three fingers around hers. + +“Does he still expect the crown-bearer?” + +“Even a ruined emperor must observe the forms.” + +“And cover the bearer's face.” + +“The god grants his attention to the ruler alone. That's what the priests say.” + +“Good. Whose men watch the western gate?” + +He was quiet for a moment. Then his hand tightened. + +“His.” + +“I will leave by it before sunset.” + +“He knows your face.” + +“Everyone knows my face.” + +She could feel Daret considering the thing she meant. Outside, the thunder moved east. Orvek had found another building to break. + +“I can send a guard to the quarry path,” he said. + +“Meet me there yourself. I will need to know where to stand.” + +He let go of her. When he spoke again, she heard the boy asking a question he knew would bring punishment. + +“What will you see?” + +“Tell me when we're there.” + +* + +They opened the western gate for her, and the waiting crowd went silent. + +Ivara disliked that silence more than she disliked the staring she could not see. She had been told all her life how people looked at her. Painters had begged for her mornings. Emperors had sent jewels to brighten a beauty she had no means of examining. For three hundred years one family of sculptors had argued about her mouth. + +Now the crowd waited for her to do something beautiful or terrible. A baby began to fuss. + +“Who has room for me?” she asked. + +A cart shaft creaked. “Here, Lady.” + +She found its side with her stick and let a woman guide her to a plank seat. The cart smelled of turnips, bedding, and a frightened dog. As it began to move, the silence broke into the sounds of people trying to get out of one another's way. + +The woman beside her was struggling to breathe evenly. + +“Have you left someone?” Ivara asked. + +“My husband. He's with the gate soldiers.” + +“What's his name?” + +The woman told her. Ivara repeated it. + +“Will you—” The woman stopped. + +“I can remember him,” Ivara said. + +The cart jolted over the threshold. A child on the floor cried out, more angry than hurt, and the dog began to bark at the wheels. + +“Don't pull his ear,” the woman said. + +“I'm not.” + +“Then why is he biting you?” + +“He's cross.” + +Ivara reached down. The dog sniffed her hand and pushed its nose against her palm. + +Above the traffic she heard hoofbeats slowing, then keeping pace. The woman beside her fell still. Men spoke quietly on horseback. One of them asked her name. + +“Ivara,” she said. + +He made a small noise, as though he had come upon a blade lying among the bedding. + +“Where are you bound?” + +“West, if this cart holds together.” + +The woman gave a surprised breath that was almost laughter. The rider moved on. Before long Ivara heard his horse running back toward the city. + +They traveled until the road dipped behind the quarry hill and the warmth of the sun left her face. The god's thunder had grown quieter, though the wind carried the distant crashes after it. Here the quarry walls would stand between the road and anyone watching from the city. + +Ivara asked to be put down. + +“There's no house here,” the woman said. + +“Someone is meeting me.” + +The child had been silent for a while. Now a small hand caught the end of the blindfold where it lay against Ivara's shoulder. The mother exclaimed and pulled the child back. + +Ivara kept her own hand over the knot until the little fingers let go. + +“Is it for your eyes?” the child asked. + +“Yes.” + +“Do they hurt?” + +“No.” + +The mother began to apologize. + +“It's a fair question,” Ivara said. “Goodbye.” + +She listened until the cart had gone. The mother was asking the child where it had put a shoe. + +At the bend, a soldier took her hand. Daret had sent him to make sure the scouts passed the quarry turn before she entered it. He told her they had ridden on toward the next village, asking whether she meant to spend the night there. + +His fingers trembled when she let him lead her off the road. + +* + +The old quarry path was steep enough that Daret had to stop twice on the last ascent. He tried to disguise the stops as directions. + +“A step to your left.” + +She took it. + +“A little farther. There's loose stone.” + +She waited beside him until he had his breath. + +Below the ridge, the wind changed. It no longer smelled of smoke and crushed grass. It had the thin, dry smell of the hollow. + +Her mother had called that valley the greenest place in the world. + +Ivara had seen it green. She had seen her father walking home with his coat over one shoulder and her sister lifting her skirts to kick a ball. She had seen her own hands grown long and pale, and the white hair that had frightened her mother when it came in. + +On the morning the power arrived, she had been standing at the upper orchard fence. She remembered a bee in a pear blossom. The blossom browned. The bee fell, and every blossom on that tree went with it. + +She had tried to blink. + +Nothing moved. Her eyelids held open; her arms stayed at her sides. She could breathe, and hear, and watch the end move outward. The next tree withered. The orchard wall slipped into a heap of dust. Where the path ran down to the houses, the grass turned white. + +Her mother had been coming up behind her with a basket. Ivara had heard it strike the ground. + +“Don't turn,” her mother had said. + +She could not have turned. She could not tell her mother that. + +The village disappeared. For a little while the roofs kept their shapes as they descended. Then she could see the fields beyond them, and the end went there too. + +Her mother's hands came over her eyes. A little light remained between the fingers. Ivara saw a distant hillside whitening before cloth followed the hands and covered everything. + +Her knees gave way. Her mother caught her, and held a crimson sash across her face, and called her by the childish name nobody had used for years. + +Later her mother grew old. Ivara learned the shapes age made by touching her face. She had no last look at her, nor at anyone after her. + +“Ivara?” + +Daret's hand was on her elbow. + +“I'm here,” she said. + +They climbed the remaining steps in darkness. At the top he put her fingers against the altar's edge. + +“Here. You'll stand with the crown. I'll kneel to your right.” + +“Where is the hollow?” + +He guided her free hand until it pointed straight ahead. + +“There.” + +She lowered it. “And beyond it?” + +“The north slope. Fir trees. The road comes around the west end of the hollow and climbs beneath them.” + +“People?” + +“The first wagons are on it already. By dawn there'll be more.” + +“They cannot stop there.” + +“They aren't stopping. But they have to climb.” + +She stood still, making the place in her mind. Empty ground in front. Living ground beyond. Behind her, down the southern face of the ridge, the city and the rest of the people waiting to leave it. + +“How much of this can they see from below?” + +“The whole altar. He chose it so they'd see.” + +“When he comes, tell me where his face is.” + +Daret took a breath. “When do I cover you?” + +“When he begins to break.” + +“Begins?” + +“Don't wait for him to stop making a sound.” + +“And if it isn't enough?” + +She found his wrist. + +“Then it isn't enough.” + +He shifted beside her. She felt him wanting certainty from her, as kings had wanted it for centuries. + +“My mother almost lost the whole valley before she understood,” she said. “We will have less time here.” + +“I'll be behind your shoulder.” + +“You may have to move me. I won't be able to move myself.” + +“I understand.” + +He took the second strip of silk from her hand and unfolded it. For a moment the wind laid its loose end against her cheek. + +“How old is your granddaughter now?” + +“Nine.” + +“When I last heard her she couldn't say my name.” + +“She can now.” + +“Does she look like you?” + +He gave a brief laugh. “She looks like her grandmother. She's lucky.” + +Ivara heard him put the cloth away. She wished she could have seen the expression that went with the laugh. + +“The north side of the altar is worn,” he told her. “There's a hollow in it where his hand goes. I can feel it.” + +She touched the stone where he guided her. Thousands of years of wind might have worn such a hollow. Or a god who put his hand in the same place whenever another emperor came to kneel. + +They waited for dawn. + +* + +The first sound from below was a horn. Another answered from farther down the western road, then another from beyond the hollow. The soldiers were passing word along the column. + +Daret put the crown in Ivara's hands. It was heavier than the one his father had worn, and its inner band had been padded where his head had grown thin. She felt that small accommodation beneath the jewels. + +“They can see us,” he said. + +He helped her raise the crown-bearer's hood. She loosened the knot of her blindfold and caught its ends in the hood's back fold. One pull would take them together. + +She kept her eyes shut beneath the cloth. + +The wind stopped. + +Ivara heard a great weight settle on the far side of the altar. The stone gave a faint, high complaint. Warmth came toward her, carrying the smell of iron. + +“You have brought only one servant.” + +The voice was smaller here, though it seemed to sound in the bones of her face. + +“As you required,” Daret said. + +“She has left you.” + +Daret said nothing. + +“My riders saw her on the western road. Your Lady will not stay to watch you die.” + +The god sounded pleased. Ivara stood with her head bowed under the hood. + +“Kneel,” Orvek said. + +Daret's left knee touched the ground. The right followed with its little click. + +“You put on the crown too willingly,” the god told him. “You forget whose hands gave it back.” + +“I remember.” + +“Then ask.” + +There was a long pause. Ivara felt a tremor pass from Daret's hand into the rim of the crown as he took hold of it. + +“Let them live,” he said. + +Orvek laughed. + +In the palace, Daret's wife had once laughed so hard that she had fallen against Ivara and gripped her arm. Ivara had tried to imagine the face that went with that helpless sound. She remembered that now, absurdly, while the god's laughter rolled over the people on the road. + +“Hold it higher.” + +The crown lifted from her fingertips. + +Daret whispered, “Here. His face is here.” + +She turned toward his voice. + +“A little higher.” + +She raised her chin. + +Orvek's breath touched her. A living breath, warm and faintly sour. His hand scraped into the worn hollow at the altar's edge as he leaned forward to take the crown and the emperor's neck. + +Ivara pulled back her hood and opened her eyes. + +The first thing she saw was a man's surprise. + +The gold of his skin had not reached the pale scar through one eyebrow. His eyes were brown. She had imagined something too large for a face, too strange for the ordinary shape of terror; instead his mouth opened and the skin beside his eyes drew tight. + +She could not move. + +“Iv—” + +Her name shook the valley. + +He tore himself backward. The hand that had been reaching for Daret swept across the altar, and its fingers lost their gold. The crown struck the stone and broke. + +Daret's knee cracked beside her. She heard his palm strike the altar as he tried to push himself up. + +Orvek grew as he fled. His shoulders rose above the ridge, his feet passed over the hollow, and the storm he had gathered around his body lifted with him. It filled the sky with black folds. Between them she saw his immense chest. + +Her body held her where she stood. She could not raise her head to follow his face, but his body still filled her sight, and he carried the ending with him. + +He called the thunder down. + +White branches reached from his hands toward the ridge. Before they struck, they frayed into thin, soundless threads. The wind hurled itself against Ivara's rigid body. + +A heel scraped behind her, then slipped. Daret grunted. + +Orvek flung his arms wide. Cloud streamed away from them. For an instant he hung across the hollow like a second range of mountains, and all the air below him darkened. + +At the edge of her vision, the altar settled. A seam of white dust opened through it. The northern tooth of the ridge, the landmark by which generations had found their way home, tipped slowly out of the sky. + +Then the light went out in one of his hands. + +It did not fall. It lost its shape, and the loss ran up his arm. Through the place where it had been, Ivara saw a green slope. + +Green. + +A color she had held in memory for a thousand years was there, alive. + +Daret's breath was close behind her ear. His hand struck her hair, then slid free. + +The firs stood in ranks up the mountain. Beneath them, little marks moved along a pale thread of road. The gap widened as the god's shoulder gave way. He was still screaming. + +She could not shut her eyes. + +Silk crossed her sight. + +Her legs folded. + +Daret caught her badly. They went down together, his arm beneath her shoulders, his other hand crushing the cloth against her eyes. She heard stones striking one another and falling away into the hollow. The ground shook under their bodies. + +“Hold still,” he gasped. + +She was holding him as hard as he held her. + +The god's voice broke off. + +For a while there was only the sound of falling stone. It went on so long that Ivara began to think the whole ridge was going down with them. Daret did not lift his hand. Dust filled her mouth, and his heart beat against her arm with painful force. + +At last the falling grew distant. + +“Daret?” + +“Here.” + +“Can you see him?” + +His breath moved against her hair. She felt him looking over her head. + +“No.” + +“The road?” + +He waited before answering. + +“The wagons are still moving.” + +She lay still beneath his hand. + +“The firs?” + +“They're green.” + +He began to laugh. It hurt him; she heard the laugh catch and turn to a cough. Then he was trying to tie the cloth with one hand and discovering that he could not. + +“Let me,” she said. + +She kept her eyelids pressed shut while he held the silk in place. Her fingers found the ends, drew them behind her head, and made a knot beneath her loosened hair. + +“Is that enough?” he asked. + +She tested the covering with two fingers. + +“Yes.” + +He took his hand away. + +* + +The storm had gone quiet. In its place she heard pebbles slipping, a torn piece of cloth flapping somewhere, Daret rubbing dust from his face. + +He got to his feet using her shoulder, then helped her stand. Where the altar had been, her stick found nothing. + +“Don't step forward.” + +“How much is gone?” + +“The altar. The outer spur. All the way down to the hollow.” + +“And the city?” + +“Still there.” + +Below them, a man shouted. The wind took his words. Another voice answered, then a horn sounded three uncertain notes. + +Daret called back. His voice was thin without the god's thunder behind it. He tried again. + +“He's gone!” + +This time someone heard. + +The words began to pass down the southern face. Men who had stood together beneath Orvek's banners were shouting them to people the god had driven from their homes. A woman called them back as a question. Daret answered her. + +No voice came out of the empty sky to stop him. + +A captain reached them while Ivara was putting up her hair. The woman was so out of breath she could only say, “Majesty,” then cough. + +“Get the column over the north pass,” Daret told her. “Before they try to come back.” + +“They saw the ridge fall. They think—” + +“We're alive.” + +The captain swallowed. “What happened?” + +Daret was quiet long enough that Ivara turned toward him. + +“I asked Ivara to kill him,” he said. “She chose to come.” + +After a moment, the captain drew a breath. “Your crown, Majesty. A piece of it. I found it on the path.” + +“Keep it for now. I need both hands.” + +The captain went down again. + +Ivara felt Daret kneel beside her. This time both knees made a sound. + +“Have you hurt yourself?” + +“No.” + +He did not get up. + +She reached until she found his face. His cheek was wet where he had wiped it with a dusty hand. There was a deep crease beside his mouth, and another between his brows. She laid her thumb there. + +“You've changed,” she said. + +“You've been told.” + +“Yes.” + +She had seen a god afraid. She had seen green trees and a broken mountain, the first new things she had looked upon in a thousand years. She had not seen this face. + +Daret leaned into her hand. + +Below them the shout was gathering strength. It moved along the western road, around the dead hollow, up toward the green pass. Somewhere in it were the woman from the cart, the child with one shoe, the gate soldiers whose names she did not yet know. + +She gave Daret her other hand and waited while he rose. + +“You'll have to tell me where to put my feet,” she said. + +He brought her hand to his elbow. + +They began to descend. The people below were calling to one another now, and before long their voices were so many that she had to lean close to hear him. diff --git a/stories/the-last-thing-heaven-saw/title-image.jpg b/stories/the-last-thing-heaven-saw/title-image.jpg new file mode 100644 index 00000000..336baf6c Binary files /dev/null and b/stories/the-last-thing-heaven-saw/title-image.jpg differ