Skip to content
Closed
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
kind: Fixed
body: Allow local Python overrides to exclude exact generated subtrees before source observation, and accept valid Hatchling source distributions whose single root directory is implicit in archive entries.
time: 2026-08-16T05:45:00+08:00
2 changes: 2 additions & 0 deletions .changes/unreleased/portable-tool-definition-design.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
kind: Docs
body: Document the accepted portable-tool composition, targeting, acquisition, identity, validation, and embedded-catalog blueprint model.
2 changes: 2 additions & 0 deletions .changes/unreleased/portable-tool-delivery-plan.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
kind: Docs
body: Add the portable tool definition implementation plan defining the reviewable PTD-01 through PTD-24 delivery order, preparation gates, and per-slice acceptance evidence.
16 changes: 10 additions & 6 deletions docs/APT_PROVIDER.md
Original file line number Diff line number Diff line change
Expand Up @@ -336,12 +336,16 @@ match.

When a staging package override selects local Python source, its filesystem
path is only a local build input. Reploy observes an immutable path-free input
digest while withholding VCS metadata, then lets the declared Python build
backend define the package boundary by producing an sdist. The backend sees
ordinary generated directories and caches; Reploy does not decide package
contents with a generic ignore list. Reploy validates and retains exactly one
closed `.tar.gz` sdist, securely extracts that retained artifact, and builds
the wheel only from the extraction.
digest while withholding VCS metadata and any exact relative subtrees listed
by the selected override's optional `exclude` array, then lets the declared
Python build backend define the package boundary by producing an sdist.
Exclusions are literal forward-slash paths, not glob or ignore-file patterns;
they are applied before Reploy reads metadata beneath the selected path and are
part of source-input identity. Selected FIFOs and other unsupported special
files remain errors. Apart from these explicit input exclusions, the backend
sees ordinary generated directories and caches. Reploy validates and retains
exactly one closed `.tar.gz` sdist, securely extracts that retained artifact,
and builds the wheel only from the extraction.

A selected snapshot may contain project-owned `.reploy.yaml` build metadata.
The initial strict recipe declares either `pep517` or `setuptools-legacy` and
Expand Down
7 changes: 5 additions & 2 deletions docs/APT_PROVIDER_DETAIL_DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -297,8 +297,11 @@ Staging package overrides are not blueprint or request-overlay entries. A
staging directory may contain `overrides.yaml`, an explicit sparse
environment overlay whose `environment.id` must match the retained blueprint.
For each provider-owned package identifier it selects exactly one local `path`
or upstream `version`. During `reploy build`, inspection of a selected local
source produces a `ResolvedSourceInput`
or upstream `version`. A local mapping may also contain an `exclude` array of
exact canonical source-relative subtrees. These are literal paths rather than
glob patterns; Reploy applies them before observing entry metadata and binds
the normalized list into local-source identity. During `reploy build`,
inspection of a selected local source produces a `ResolvedSourceInput`
containing the source-input digest, retained source-artifact digest,
build-environment digest, builder/toolchain profile, settings, ecosystem
metadata, and output-artifact digest. The resolved request and its digest live
Expand Down
131 changes: 125 additions & 6 deletions docs/BLUEPRINT_ENVIRONMENT_MODEL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
status: Active
updated: 2026-08-08
updated: 2026-08-16
summary: Normative blueprint environment, workload, application, provider contribution, lifecycle, and Docker rendering model.
supersedes: docs/CROSS_PLATFORM_INSTALL_LOCATIONS.md
---
Expand Down Expand Up @@ -639,8 +639,9 @@ unrelated option does not invalidate every provider node.
All providers use one common identity contract when a staging package override
builds an artifact from local source. The source path locates the source for
the local build but is not content identity. Reploy observes a canonical
source-input digest, while the provider defines and validates the closed source
artifact that crosses into the final build. The identity also binds the
source-input digest over both the selected entries and any explicit input
exclusions, while the provider defines and validates the closed source artifact
that crosses into the final build. The identity also binds the
versioned builder and toolchain profile, every relevant build setting, and a
build-environment digest covering the selected platform, immutable upstream
image, and selected toolchain evidence.
Expand Down Expand Up @@ -812,7 +813,31 @@ the blueprint. It names `environment.id`, may replace the base reference at
`environment.package_overrides`. Absence of `environment.base` means **From
blueprint**. Each package mapping selects either a local source path or a
specific version from that provider's normal upstream source. The two package
forms are mutually exclusive.
forms are mutually exclusive. A local-path mapping may also declare `exclude`,
an array of exact source-relative paths whose named entry and descendants are
withheld from the immutable source input:

```yaml
environment:
id: omegaflow
vars:
workspace_root: /home/me/src
package_overrides:
python:
omegaflow:
path: "{{ workspace_root }}/omegaflow"
exclude:
- recordings/.omegaflow
```

Each exclusion is a canonical relative path using `/`. Absolute paths,
escaping `..` components, backslashes, glob syntax, and duplicates are
rejected. The list is normalized into lexical order for identity. Reploy
matches each path literally and excludes that path and its complete subtree;
it does not read `.gitignore` or interpret ignore-file patterns. Exclusion is
performed during source walking before file metadata beneath the excluded path
is read, so generated FIFOs may be excluded deliberately. A FIFO or other
unsupported special file that remains selected is still a hard error.

The same sidecar may contain explicit development-only package roots beneath
`environment.package_additions`. These are install requests, unlike source
Expand Down Expand Up @@ -876,8 +901,9 @@ mappings on the user's behalf, but resolution must not add inferred packages,
resolved dependencies, hashes, or selected artifacts to it. Those results
belong in the generated build lock and closed bundle. Relative local paths are
resolved from the sidecar's directory; absolute paths are also valid. Physical
paths never enter resolved content identity. Installation consumes the staged
bundle and never reads the sidecar or original source checkout.
paths never enter resolved content identity; the normalized exclusion intent
does. Installation consumes the staged bundle and never reads the sidecar or
original source checkout.

`reploy overrides [--dir DIR]` opens the native editor for the current,
default, or explicitly selected staging directory and loads an existing
Expand All @@ -892,6 +918,9 @@ the current user's home is expanded when Reploy uses the override. It lists
explicit blueprint, selected-option, and deployment-added package requirements
first with a distinct shaded background; override-only mappings follow. These
variables belong to the sidecar and are not blueprint variables.
The editor displays the number of exclusions and preserves an existing local
choice's `exclude` list, but does not yet provide controls for authoring it; add
or change exclusions directly in `overrides.yaml`.

`V` saves the current choices and runs the normal build pipeline as an optional
trial validation. Success means the selected versions exist, dependency
Expand Down Expand Up @@ -977,6 +1006,8 @@ environment:
python:
arbiter-server:
path: "{{ workspace_root }}/server"
exclude:
- recordings/.arbiter
arbiter-imap:
path: "{{ workspace_root }}/plugins/imap"
arbiter-smtp:
Expand All @@ -1000,6 +1031,94 @@ local source or upstream-version form that it cannot materialize.
The same application/package ownership model can be extended to other build
and packaging systems later.

## Proposed Embedded Built-In Tools

This section describes the support surface proposed for the embedded
portable-tool implementation. The current blueprint schema does not yet accept
`packages.tools`; the example and behavior below become normative only when
that implementation lands.

Until the portable-tool repository is implemented, Reploy will ship a
deliberately small catalog of reviewed tool definitions inside the binary.
These definitions will be versioned implementation data, not a general
repository or an extension point. Changing one will require a new Reploy
binary. Runtime tools will contribute their selected definition-closure digest
to provider identity.

The concrete catalog structure, exact target tuple, acquisition composition,
and selected-closure identity are specified by the
[Portable Tool Definition Design](PORTABLE_TOOL_DEFINITION_DESIGN.md). This
section defines the proposed user-facing blueprint behavior and support
surface.

The initial runtime tool will be Playwright 1.61.0 with its Python binding and
Chromium selection:

```yaml
environment:
base:
image: python:3.13-slim-bookworm
exports:
python:
executable: /usr/local/bin/python
applications:
application:
packages:
tools:
# Proposed; not accepted by the current blueprint schema.
- tool: playwright
version: "1.61.0"
binding: python
select: [chromium]
```

`tool` and `select` will be required. When `version` is omitted, Reploy will
select the newest eligible upstream release and definition revision, matching
the repository-backed resolver; explicitly naming `version: "1.61.0"` as above
will constrain that selection. Because `python` is the only binding, Reploy
will infer it when `binding` is omitted; explicitly naming `binding: python` as
above will be equivalent. The embedded definition will declare the complete
Python requirement roots (`playwright==1.61.0`, `pyee>=13,<14`, and
`greenlet>=3.1.1,<4.0.0`), pin the exact Linux AMD64 Playwright wheel, and
record its bundled Node.js 24.17.0 and `playwright-core`
1.61.1-beta-1782139630000 constituents. The Python provider will resolve the
declared closure and reject a Playwright wheel whose filename, tags, size, or
SHA-256 digest differs from the definition.

Each supported target will be exact to the platform, `/etc/os-release` `ID` and
`VERSION_ID`, native package architecture, and package manager. Reploy will not
infer a target from the image tag or merge package lists across OS generations.
Providers will select one exact target after observing the base image and retain
the selected definition closure in locked provider identity. Shared tool,
release, binding, and payload records may be reused explicitly; target leaves
will retain only the compatibility and package data specific to their exact OS
and architecture.

The reviewed native Chromium dependencies will also be definition-owned. The
`chromium` selection will include Playwright's coupled full Chromium, Chromium
Headless Shell, and FFmpeg payloads. Reploy will acquire their exact revisions,
verify their sizes and SHA-256 digests, then materialize them with networking
disabled. Neither resolution nor materialization will invoke `playwright
install` or `playwright install-deps`. The final image will set
`PLAYWRIGHT_BROWSERS_PATH` to the Reploy-owned browser directory and disable
Playwright's browser download and garbage-collection behavior. The application
will continue to run as the configured non-root runtime user.

This built-in definition will support Debian 12 (`bookworm`), Ubuntu 25.10
(`questing`), and Ubuntu 26.04 LTS (`resolute`) on `linux/amd64`, with the
Python binding and `chromium` selection. Other versions, bindings, browsers,
operating systems, or architectures will fail before artifact acquisition.
Ubuntu targets will own their `t64` package names independently from Debian.
The prebuilt Microsoft Playwright image will be neither required nor used.

The existing local-source Java build requirement will become `tool:java==21`
and resolve definition revision 1 to Eclipse Temurin JDK `21.0.12+8` in the
embedded catalog for Debian 12, Debian 13, Ubuntu 25.10, and Ubuntu 26.04. Its
ownership behavior will remain unchanged: it will contribute the pinned JDK,
including `java` and `javac`, only to the isolated source builder and will not
add Java to the application runtime. Distribution-default Java packages are not
a fallback.

## Possible Shape

```yaml
Expand Down
Loading
Loading