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
41 changes: 41 additions & 0 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,47 @@ jobs:
- name: Run pipeline test suite (per-pipeline + v0.6 cross-cutting)
run: python tools/test_pipelines.py

runtime-scaffold:
name: v0.9 runtime scaffold (sub-issue #120)
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.11", "3.12"]

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install runtime package (editable)
run: |
python -m pip install --upgrade pip
python -m pip install -e .

- name: Run runtime-scaffold test suite
run: python tools/test_runtime_scaffold.py

- name: Confirm `lifectl` console script installed
run: |
lifectl version
# exit non-zero on info / run is expected (scaffold-only stubs)
set +e
lifectl info pretend.life
info_rc=$?
lifectl run pretend.life
run_rc=$?
set -e
if [ "$info_rc" -eq 0 ] || [ "$run_rc" -eq 0 ]; then
echo "ERROR: lifectl info/run unexpectedly succeeded in scaffold-only build"
exit 1
fi
echo "scaffold stubs exit non-zero as expected (info=$info_rc, run=$run_rc)"

docs:
name: Lint docs (markdownlint + linkcheck)
runs-on: ubuntu-latest
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ __pycache__/
*.pyc
.venv/
.env
*.egg-info/
build/
dist/

# Never commit raw high-risk personal data
*.mp4
Expand Down
72 changes: 72 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,78 @@

All notable changes to the DLRS project will be documented in this file.

## v0.9 — Reference Runtime Implementation (in progress)

**Status**: Epic
[#119](https://github.com/Digital-Life-Repository-Standard/DLRS/issues/119)
open. Goal: ship the reference runtime for `life-runtime v0.1.1`
(v0.7 §1–10 + v0.8 Part B 5-stage assembly), single `.life` only.
Multi-`.life`, `.world` and DLRS Extension Architecture remain v0.10+.

Sub-issues:
[#120](https://github.com/Digital-Life-Repository-Standard/DLRS/issues/120)
scaffold,
[#121](https://github.com/Digital-Life-Repository-Standard/DLRS/issues/121)
Stage 1 Verify,
[#122](https://github.com/Digital-Life-Repository-Standard/DLRS/issues/122)
Stage 2 Resolve,
[#123](https://github.com/Digital-Life-Repository-Standard/DLRS/issues/123)
Stage 3 Assemble,
[#124](https://github.com/Digital-Life-Repository-Standard/DLRS/issues/124)
Stage 4 Run,
[#125](https://github.com/Digital-Life-Repository-Standard/DLRS/issues/125)
Stage 5 Guard,
[#126](https://github.com/Digital-Life-Repository-Standard/DLRS/issues/126)
echo Provider + e2e conformance harness + Quickstart docs.

### Added (sub-issue #120 — scaffold)

- `runtime/` Python package (`runtime/__init__.py` exporting `__version__
= "0.9.0.dev0"` and `LIFE_RUNTIME_PROTOCOL_VERSION = "0.1.1"`) with
empty sub-packages laid out for the 5 assembly stages: `verify/`,
`resolve/`, `assemble/`, `run/`, `guard/`, plus `providers/` (built-in
Provider implementations) and `audit/` (runtime-side hash-chain
emitter). Each empty stage carries a one-line docstring naming the
sub-issue that populates it.
- `runtime/cli/lifectl.py` — `lifectl` CLI entrypoint with three
sub-commands. `lifectl version` prints `lifectl 0.9.0.dev0
(life-runtime v0.1.1)` and exits 0. `lifectl info <pkg>` and
`lifectl run <pkg>` parse their arguments but exit non-zero with a
"not yet implemented in this sub-issue" message that points the
reader at the right follow-up sub-issue (#121 / #121-#126).
- `pyproject.toml` at repo root — declares `dlrs-runtime` package
(`name = "dlrs-runtime"`, `version = "0.9.0.dev0"`, `requires-python
>= 3.10`, deps `jsonschema` + `pyyaml`) and exports the `lifectl`

Check failure on line 46 in CHANGELOG.md

View workflow job for this annotation

GitHub Actions / Lint docs (markdownlint + linkcheck)

Spaces inside code span elements

CHANGELOG.md:46:40 MD038/no-space-in-code Spaces inside code span elements [Context: "`) and exports the `"] https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md038.md

Check failure on line 46 in CHANGELOG.md

View workflow job for this annotation

GitHub Actions / Lint docs (markdownlint + linkcheck)

Spaces inside code span elements

CHANGELOG.md:46:10 MD038/no-space-in-code Spaces inside code span elements [Context: "`, deps `"] https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md038.md
console script via `[project.scripts]`. Setuptools is told to
package only `runtime*` so the existing `tools/` and `pipelines/`

Check failure on line 48 in CHANGELOG.md

View workflow job for this annotation

GitHub Actions / Lint docs (markdownlint + linkcheck)

Spaces inside code span elements

CHANGELOG.md:48:3 MD038/no-space-in-code Spaces inside code span elements [Context: "package only `"] https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md038.md
trees stay out of the wheel.
- `runtime/audit/emitter.py` — `RuntimeAuditEmitter` stub class that
raises `NotImplementedError` referencing sub-issue #125 (the full
v0.4 hash-chain emitter ships there).
- `runtime/README.md` — package-level overview pointing at the runtime
spec and naming each sub-package's owning sub-issue.
- `tools/test_runtime_scaffold.py` — eight sanity-test cases covering
package import, `Runtime` stub class, `lifectl version` output, the
scaffold-only stub exits, `lifectl --help` listing all three
sub-commands, the parseability of `pyproject.toml` (asserting the
`lifectl` console-script entry), and that all eight `runtime/`
sub-packages exist.
- `.github/workflows/validate.yml` — new `runtime-scaffold` CI job
parallel to the existing `pipelines` job, matrix Python 3.11 + 3.12.
Installs `dlrs-runtime` editable, runs the scaffold test driver, and
asserts both that the `lifectl` console-script is on `PATH` (`lifectl
version` succeeds) and that `lifectl info` / `lifectl run` exit
non-zero in the scaffold-only build.

### Hard-rule invariants preserved

This sub-issue ships no execution code, so the v0.7 + v0.8 hard-rule
invariants (D1=C in-life sandbox / D2=B `bundled_in_life` Provider
refusal / D5=mixed hosted-API AND-gate / D6=fail-close Stage gating)
are upheld trivially: the scaffold cannot violate them because none of
the gates run yet. Sub-issues #121–#126 reinstate each invariant as
they implement the corresponding Stage.

## v0.8-asset-architecture (2026-04-26)

**Status**: Released. v0.8 closes the four asset-architecture gaps left
Expand Down Expand Up @@ -42,7 +114,7 @@
`compute.hosted_api_used: true` requires at least one entry in
`compute.hosted_api_providers[]`. [#101]
- `tools/test_genesis_schema.py` — 36 sanity-test cases (4 happy-path
+ 32 negative) wired into `tools/batch_validate.py`. [#101]

Check failure on line 117 in CHANGELOG.md

View workflow job for this annotation

GitHub Actions / Lint docs (markdownlint + linkcheck)

Unordered list style

CHANGELOG.md:117:1 MD004/ul-style Unordered list style [Expected: dash; Actual: plus] https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md004.md
- `docs/LIFE_LIFECYCLE_SPEC.md` — per-topic normative spec for Topic 2
(Asset Lifecycle). Defines four document shapes
(`package_lifecycle`, `asset_lifecycle`, `mutation_event`,
Expand Down Expand Up @@ -84,7 +156,7 @@
non-`x-` keys reject statically (decision D4=C fail-close at schema
layer). [#103]
- `tools/test_binding_schema.py` — 63 sanity-test cases (11 happy-path
+ 52 negative) wired into `tools/batch_validate.py`. The 63 includes

Check failure on line 159 in CHANGELOG.md

View workflow job for this annotation

GitHub Actions / Lint docs (markdownlint + linkcheck)

Unordered list style

CHANGELOG.md:159:1 MD004/ul-style Unordered list style [Expected: dash; Actual: plus] https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md004.md
three negatives for `providers_whitelist_ref` path-traversal (added
in #111 review fix-up) and eight more cases (6 negative + 2 happy)
for path-traversal rejection on `surface.ui_hints.avatar_image_ref`
Expand All @@ -111,7 +183,7 @@
`LIFE_TIER_SPEC.md` so future naming schemes can ship without a
spec major bump. [#104]
- `tools/test_tier_schema.py` — 81 sanity-test cases (26 happy-path
+ 55 negative) covering both ends of every score → level range,

Check failure on line 186 in CHANGELOG.md

View workflow job for this annotation

GitHub Actions / Lint docs (markdownlint + linkcheck)

Unordered list style

CHANGELOG.md:186:1 MD004/ul-style Unordered list style [Expected: dash; Actual: plus] https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md004.md
every score → level mismatch boundary, every required-field
removal, every dimension off-enum, and the auto-computation guard
on `computed_by`. Wired into `tools/batch_validate.py`. [#104]
Expand Down Expand Up @@ -178,7 +250,7 @@
[#104]: https://github.com/Digital-Life-Repository-Standard/DLRS/issues/104
[#105]: https://github.com/Digital-Life-Repository-Standard/DLRS/issues/105


Check failure on line 253 in CHANGELOG.md

View workflow job for this annotation

GitHub Actions / Lint docs (markdownlint + linkcheck)

Multiple consecutive blank lines

CHANGELOG.md:253 MD012/no-multiple-blanks Multiple consecutive blank lines [Expected: 1; Actual: 2] https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md012.md
## v0.7-vision-shift (2026-04-26)

**Status**: Released. Repositions DLRS's ULTIMATE from "Digital Life
Expand All @@ -186,7 +258,7 @@
to "**`.life` 可运行数字生命档案文件标准**" — a dual standard:

1. **`.life` archive file format** — the distribution unit, a packaged
+ signed subset of a DLRS v0.6 record.

Check failure on line 261 in CHANGELOG.md

View workflow job for this annotation

GitHub Actions / Lint docs (markdownlint + linkcheck)

Unordered list style

CHANGELOG.md:261:1 MD004/ul-style Unordered list style [Expected: dash; Actual: plus] https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md004.md
2. **`.life` runtime protocol** — how compatible runtimes load + execute
a `.life` to produce an *AI digital life instance*.

Expand All @@ -199,7 +271,7 @@
under milestone
[`.life Archive + Runtime Standard (v0.7-vision-shift)`](https://github.com/Digital-Life-Repository-Standard/DLRS/milestone/5).
All 8 sub-issues #80–#87 closed; PRs #88, #89, #91, #92, #93, #94,
#95, #97, #98 merged.

Check failure on line 274 in CHANGELOG.md

View workflow job for this annotation

GitHub Actions / Lint docs (markdownlint + linkcheck)

No space after hash on atx style heading

CHANGELOG.md:274:1 MD018/no-missing-space-atx No space after hash on atx style heading [Context: "#95, #97, #98 merged."] https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md018.md

This epic ships **specs + schema + example builder**. It does **not**
ship a working runtime — that is deferred to v0.8+.
Expand Down Expand Up @@ -513,7 +585,7 @@

### Closes

#28 (epic), #29, #30, #31, #32, #33, #34, #35, #36, #37, #38.

Check failure on line 588 in CHANGELOG.md

View workflow job for this annotation

GitHub Actions / Lint docs (markdownlint + linkcheck)

No space after hash on atx style heading

CHANGELOG.md:588:1 MD018/no-missing-space-atx No space after hash on atx style heading [Context: "#28 (epic), #29, #30, #31, #32..."] https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md018.md

---

Expand Down
47 changes: 47 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
[build-system]
requires = ["setuptools>=68", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "dlrs-runtime"
version = "0.9.0.dev0"
description = "DLRS reference runtime — `life-runtime v0.1.1` reference implementation."
readme = "runtime/README.md"
requires-python = ">=3.10"
license = { file = "LICENSE" }
authors = [
{ name = "DLRS contributors" },
]
keywords = ["dlrs", "life", "digital-life", "runtime"]
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"License :: OSI Approved :: Apache Software License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Software Development :: Libraries",
]
dependencies = [
"jsonschema>=4.0.0",
"pyyaml>=6.0.0",
]

[project.optional-dependencies]
dev = [
"pytest>=7.0.0",
]

[project.scripts]
lifectl = "runtime.cli.lifectl:main"

[project.urls]
Homepage = "https://github.com/Digital-Life-Repository-Standard/DLRS"
Repository = "https://github.com/Digital-Life-Repository-Standard/DLRS"
Issues = "https://github.com/Digital-Life-Repository-Standard/DLRS/issues"
Spec = "https://github.com/Digital-Life-Repository-Standard/DLRS/blob/master/docs/LIFE_RUNTIME_STANDARD.md"

[tool.setuptools.packages.find]
include = ["runtime*"]
exclude = ["tools*", "pipelines*", "examples*", "tests*"]
52 changes: 52 additions & 0 deletions runtime/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# `runtime/` — DLRS reference runtime

Reference implementation of the `life-runtime v0.1.1` protocol defined in
[`docs/LIFE_RUNTIME_STANDARD.md`](../docs/LIFE_RUNTIME_STANDARD.md).

Tracking epic: [#119](https://github.com/Digital-Life-Repository-Standard/DLRS/issues/119)
(v0.9 — Reference Runtime Implementation).

## Layout

```
runtime/
├── __init__.py exports __version__ + Runtime stub
├── cli/lifectl.py lifectl CLI entrypoint
├── verify/ Stage 1 — sub-issue #121
├── resolve/ Stage 2 — sub-issue #122
├── assemble/ Stage 3 — sub-issue #123
├── run/ Stage 4 — sub-issue #124
├── guard/ Stage 5 — sub-issue #125
├── providers/ built-in echo Provider — sub-issue #126
└── audit/ runtime-side hash-chain emitter — sub-issue #125
```

## Quickstart (post-v0.9)

```
pip install -e . # from repo root
lifectl version # confirm install
lifectl run examples/minimal-life-package/out/*.life
```

Until v0.9 sub-issues #121-#126 land, `lifectl info` and `lifectl run` exit
with a "not yet implemented in this sub-issue" message — only `lifectl version`
is functional.

## Why a separate Python package?

The repo's existing `tools/` directory hosts authoring + validation tooling
(builders, schema linters, pipeline drivers). The runtime is a different
artifact: it loads a finished `.life`, not authors one. Separating the two
keeps the dependency graph clean — `tools/` continues to work with
`tools/requirements.txt`, while `runtime/` is installable via
`pyproject.toml` (`pip install -e .`).

## Spec conformance

`life-runtime v0.1.1` includes everything from v0.1 (load sequence, mount
semantics, runtime obligations, termination) plus v0.8 Part B 5-stage
assembly + Provider Registry + graded sandbox + hosted-API AND-gate.
The `runtime/` package implements **the full v0.1.1 spec** for **single
`.life`** sessions only — multi-`.life` ensemble + `.world` + plugins are
v0.10+ work.
36 changes: 36 additions & 0 deletions runtime/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""DLRS reference runtime — `life-runtime v0.1.1` reference implementation.

This package implements the protocol defined in
``docs/LIFE_RUNTIME_STANDARD.md`` (v0.7 §1-10 + v0.8 Part B 5-stage assembly).

Public surface today (v0.9 sub-issue #120 — scaffold only):

- ``__version__`` — runtime package version (``0.9.0.dev0``).
- ``LIFE_RUNTIME_PROTOCOL_VERSION`` — declared life-runtime spec version.
- ``Runtime`` — placeholder class; concrete assembly stages land in sub-issues
#121-#126.

The ``runtime.cli.lifectl`` module exposes the ``lifectl`` console script.
"""

from __future__ import annotations

__version__ = "0.9.0.dev0"
LIFE_RUNTIME_PROTOCOL_VERSION = "0.1.1"


class Runtime:
"""Stub Runtime class. Concrete behaviour added in sub-issues #121-#126."""

def __init__(self) -> None:
self.version = __version__
self.protocol = LIFE_RUNTIME_PROTOCOL_VERSION

def __repr__(self) -> str:
return (
f"Runtime(version={self.version!r}, "
f"protocol={self.protocol!r}, stages_implemented=[])"
)


__all__ = ["__version__", "LIFE_RUNTIME_PROTOCOL_VERSION", "Runtime"]
1 change: 1 addition & 0 deletions runtime/assemble/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Stage 3 — Assemble. Populated in v0.9 sub-issue #123."""
4 changes: 4 additions & 0 deletions runtime/audit/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"""Runtime-side audit emitter (v0.4 hash chain).

Stub in v0.9 sub-issue #120; full implementation lands in #125 (Stage 5 Guard).
"""
17 changes: 17 additions & 0 deletions runtime/audit/emitter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"""Runtime audit emitter — STUB.

Sub-issue #120 lays down the module surface; sub-issue #125 (Stage 5 Guard)
populates the full hash-chain implementation that re-uses the v0.4 audit
event vocabulary.
"""

from __future__ import annotations


class RuntimeAuditEmitter:
"""Placeholder. Concrete emitter ships with v0.9 sub-issue #125."""

def __init__(self, *_args: object, **_kwargs: object) -> None: # noqa: D401
raise NotImplementedError(
"RuntimeAuditEmitter lands in v0.9 sub-issue #125 (Stage 5 Guard)."
)
1 change: 1 addition & 0 deletions runtime/cli/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""DLRS runtime CLI entrypoints (``lifectl``)."""
Loading
Loading