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
67 changes: 6 additions & 61 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ jobs:
grep -Eq '^Signed-off-by: .+ <[^>]+>$'
done

publication-scan:
hygiene:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
fetch-depth: 0
- name: Scan pristine tracked, untracked, ignored, and reachable Git content
run: python scripts/verify_public_plugin_candidate.py --root . --layout destination
- name: Check the tree for real secrets and unexpected endpoints
run: python3 scripts/check_public_hygiene.py --root .

test:
strategy:
Expand All @@ -56,65 +56,10 @@ jobs:
cache-dependency-glob: uv.lock
- run: uv sync --frozen --extra dev
- run: uv run --frozen --extra dev ruff check .
- run: uv run --frozen --extra dev python -m compileall -q src scripts
- run: uv run --frozen --extra dev python -m compileall -q plugins scripts
- run: uv run --frozen --extra dev python -m pytest -q


release-artifact:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
fetch-depth: 0
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.11"
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
with:
version: "0.11.32"
enable-cache: true
cache-dependency-glob: uv.lock
- run: uv sync --frozen --extra dev
- name: Re-run the complete privacy-safe migration matrix
run: |
set -euo pipefail
uv run --frozen --extra dev python scripts/benchmark_migration.py \
--manifest benchmarks/hermes-migration-manifest.json \
--profile ci \
--output "$RUNNER_TEMP/hermes-migration-baseline.json"
uv run --frozen --extra dev python scripts/verify_fresh_migration_run.py \
--receipt "$RUNNER_TEMP/hermes-migration-baseline.json"
- name: Build twice and verify deterministic bytes
env:
HERMES_PLUGIN_SOURCE_COMMIT: ${{ github.sha }}
run: |
set -euo pipefail
uv run --frozen --extra dev python scripts/build_plugin.py
cp dist/substrate_wiki.zip "$RUNNER_TEMP/first-substrate_wiki.zip"
rm -rf dist release-assets
uv run --frozen --extra dev python scripts/build_plugin.py
cmp "$RUNNER_TEMP/first-substrate_wiki.zip" dist/substrate_wiki.zip
uv run --frozen --extra dev python scripts/build_plugin.py --check
- name: Install exact artifact and reject a wrong digest
run: |
set -euo pipefail
archive_sha="$(sha256sum dist/substrate_wiki.zip | cut -d ' ' -f1)"
uv run --frozen --extra dev python scripts/install_hermes_plugin.py \
--archive dist/substrate_wiki.zip \
--hermes-home "$RUNNER_TEMP/hermes" \
--sha256 "$archive_sha" \
--no-activate --no-onboard \
--yes --json
test -f "$RUNNER_TEMP/hermes/plugins/substrate_wiki/plugin.yaml"
if uv run --frozen --extra dev python scripts/install_hermes_plugin.py \
--archive dist/substrate_wiki.zip \
--hermes-home "$RUNNER_TEMP/tamper-canary" \
--sha256 "$(printf '0%.0s' {1..64})" \
--no-activate --no-onboard \
--yes --json; then
echo "installer accepted a wrong digest" >&2
exit 1
fi
- run: uv run --frozen --extra dev python scripts/build_release.py
- run: uv run --frozen --extra dev python scripts/build_release.py --check

dependency-review:
if: github.event_name == 'pull_request'
Expand Down
40 changes: 15 additions & 25 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ jobs:
outputs:
release_version: ${{ steps.metadata.outputs.release_version }}
artifact_digest: ${{ steps.release_artifact.outputs.artifact-digest }}
env:
PYTHONPATH: src
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
Expand All @@ -44,7 +42,7 @@ jobs:
- name: Scan the pristine candidate before installing dependencies
run: |
set -euo pipefail
python scripts/verify_public_plugin_candidate.py --root . --layout destination
python3 scripts/check_public_hygiene.py --root .
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.11"
Expand All @@ -59,31 +57,24 @@ jobs:
id: metadata
run: |
set -euo pipefail
version="$(python -c 'from pathlib import Path; print(next(line.split(":", 1)[1].strip() for line in Path("src/substrate_wiki/plugin.yaml").read_text().splitlines() if line.startswith("version: ")))')"
version="$(python -c 'from pathlib import Path; print(next(line.split(":", 1)[1].strip() for line in Path("plugins/substrate/plugin.yaml").read_text().splitlines() if line.startswith("version: ")))')"
test -n "$version"
test "$version" = "0.3.0"
uv run --no-sync ruff check .
uv run --no-sync python -m compileall -q src scripts
uv run --no-sync python -m compileall -q plugins scripts
uv run --no-sync python -m pytest -q
uv run --no-sync python scripts/verify_migration_baseline.py
uv run --no-sync python scripts/benchmark_migration.py \
--profile ci \
--output "$RUNNER_TEMP/hermes-migration-baseline.json"
uv run --no-sync python scripts/verify_fresh_migration_run.py \
--receipt "$RUNNER_TEMP/hermes-migration-baseline.json"
printf 'release_version=%s\n' "$version" >> "$GITHUB_OUTPUT"
- name: Build and verify exact release bytes twice
env:
HERMES_PLUGIN_SOURCE_COMMIT: ${{ inputs.candidate_sha }}
run: |
set -euo pipefail
uv run --no-sync python scripts/build_plugin.py
cp dist/substrate_wiki.zip "$RUNNER_TEMP/first-substrate_wiki.zip"
rm -rf dist release-assets
uv run --no-sync python scripts/build_plugin.py
cmp "$RUNNER_TEMP/first-substrate_wiki.zip" dist/substrate_wiki.zip
uv run --no-sync python scripts/build_plugin.py --check
cp scripts/install_hermes_plugin.py dist/install_hermes_plugin.py
(cd dist && sha256sum install_hermes_plugin.py substrate_wiki.zip > SHA256SUMS)
uv run --no-sync python scripts/build_release.py
cp dist/substrate.zip "$RUNNER_TEMP/first-substrate.zip"
rm -rf dist
uv run --no-sync python scripts/build_release.py
cmp "$RUNNER_TEMP/first-substrate.zip" dist/substrate.zip
uv run --no-sync python scripts/build_release.py --check
- name: Upload exact verified release bytes
id: release_artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
Expand Down Expand Up @@ -115,9 +106,9 @@ jobs:
set -euo pipefail
test -n "${{ needs.verify.outputs.artifact_digest }}"
test "$(find dist -maxdepth 1 -type f -printf '%f\n' | sort | tr '\n' ' ')" = \
"SHA256SUMS install_hermes_plugin.py substrate_wiki.zip "
"SHA256SUMS substrate.zip "
(cd dist && sha256sum -c SHA256SUMS)
- uses: actions/attest-build-provenance@e3fe62ef559997059fe8380e7d2b4c909e2d65f4 # pinned
- uses: actions/attest-build-provenance@e3fe62ef559997059fe8380e7d2b64c4f677262 # pinned
with:
subject-path: "dist/*"
- name: Create immutable tag and GitHub release
Expand All @@ -141,10 +132,9 @@ jobs:
exit 1
fi
gh release create "$tag" \
dist/substrate_wiki.zip \
dist/install_hermes_plugin.py \
dist/substrate.zip \
dist/SHA256SUMS \
--repo "$GITHUB_REPOSITORY" \
--verify-tag \
--title "substrate_wiki $tag" \
--notes "Patch release for explicit post-approval history consent, reliable device-poll completion, and the Substrate v5 history-only handshake. Targets Hermes 0.20.x. See COMPATIBILITY.md and SECURITY.md."
--title "substrate $tag" \
--notes "Substrate retrieval plugin for Hermes 0.21.x: one-prompt install, self-contained RFC 8628 device onboarding, memory_search/memory_expand/memory_evidence. See README.md and COMPATIBILITY.md."
5 changes: 4 additions & 1 deletion BOUNDARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ This boundary is declared on day one and will not be moved later. Substrate asks

## Current implementation status

The pending `v1.5.0` candidate contains the Hermes `substrate_wiki` plugin/client, local spool and checkpoint machinery, client-side credential redaction, history replay, deterministic packaging, and installation tooling. It requires a configured Substrate server. No `v1.5.0` tag or release exists yet.
Release `v0.3.0` contains the Hermes `substrate` retrieval plugin: hook and tool
registration, verified transport, device onboarding with profile-private credential
custody, session-completion capture, client-side redaction, deterministic packaging, and
installation tooling. It requires a configured Substrate server.

The local runtime, local entity model, privacy-deletion implementation, and policy compiler are on the open side of the permanent boundary but are **not implemented in this candidate**. The candidate does not authorize agent actions and does not provide a no-server mode. Those absences are explicit product gaps, not held commercial features.

Expand Down
18 changes: 14 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
# Changelog

## Unreleased

- Add the current `substrate` plugin (`plugins/substrate`, version 0.2.x) for Hermes 0.21.x: one-prompt `hermes plugins install` of the subdirectory, self-contained RFC 8628 device onboarding on first use (browser approval link, background polling, key stored privately in the active profile's `.env`), `memory_search`/`memory_expand`/`memory_evidence` tools, verified TLS with bundled public ISRG root anchors, and health-gated legacy cutover. The legacy `substrate_wiki` 2.0.x provider below remains only for existing Hermes 0.20.x installations.
## 0.3.0

- First full release of the `substrate` plugin for Hermes 0.21.x: one-prompt install
from the `v0.3.0` tag, self-contained RFC 8628 device onboarding with agent display
names, `memory_search`/`memory_expand`/`memory_evidence`, live session completion
markers, pinned public ISRG trust roots, and health-gated legacy cutover.
- Remove the legacy `substrate_wiki` provider, its installer/builder, migration
benchmarks, release assets, and publication-policy machinery. The repository now
contains only the current plugin, its tests, and a deterministic release builder.
- Replace the closed-inventory publication scanner with a dependency-free public
hygiene check (`scripts/check_public_hygiene.py`).

- Add the current `substrate` plugin (`plugins/substrate`, now version 0.3.0) for Hermes 0.21.x: one-prompt `hermes plugins install` of the subdirectory, self-contained RFC 8628 device onboarding on first use (browser approval link, background polling, key stored privately in the active profile's `.env`), `memory_search`/`memory_expand`/`memory_evidence` tools, verified TLS with bundled public ISRG root anchors, and health-gated legacy cutover. The legacy `substrate_wiki` 2.0.x provider below remains only for existing Hermes 0.20.x installations.
- Let hosted onboarding validate only the history replay contract, so a setup-and-upload MVP does not need to advertise entity retrieval features.
- Add an explicit `SUBSTRATE_WIKI_ORIGIN` override for isolated v5 import tests; the hosted origin remains the default.

Expand Down Expand Up @@ -64,4 +74,4 @@ All notable changes to the public `substrate_wiki` plugin are recorded here.
- Imported byte-for-byte from Substrate-v2. Archive SHA-256: `877ccf9b0212792b699d9c98912a26980675a6050df3bd319e927639e3d901f1`.
- Original source commit: `a3953b0512bbb84fb62b48a75bab04cbcb845c78`.

Earlier immutable artifacts remain under `legacy-assets/` with their original provenance.
Earlier immutable artifacts remain under `legacy-assets/` with their original provenance.
42 changes: 12 additions & 30 deletions COMPATIBILITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,27 @@

Compatibility has three independent axes: Hermes host, hosted Substrate capability contract, and plugin version.

## Current install target

The current Hermes plugin is [`plugins/substrate`](plugins/substrate) (`substrate`, version
0.2.x). It is the only path an installing agent should select from this repository, and it is
certified for Hermes **0.21.x**. It installs with
`hermes plugins install Substrate-memory/Substrate-memory-plugins/plugins/substrate --no-enable`,
runs RFC 8628 device onboarding by itself, and registers `memory_search`, `memory_expand`,
and `memory_evidence`. It never requires a pre-existing API key.

The table below is the **legacy** `substrate_wiki` provider record. It does not apply to the
current `substrate` plugin, and it must not be used to reject a Hermes 0.21.x install: the
legacy rows exist only for existing 0.20.x installations and migration testing.

## Legacy certified matrix (substrate_wiki)
## Certified matrix

| Plugin | Hermes | Required hosted capabilities | Status |
|---|---|---|---|
| 2.0.5 | 0.20.x | Same as 2.0.4; explicit post-approval history consent and v5 handshake | Contract and lifecycle integration tested |
| 2.0.4 | 0.20.x | Same as 2.0.3; compact user/assistant capture and batched history upload | Contract and lifecycle integration tested |
| 2.0.3 | 0.20.x | Same as 2.0.2; resilient approved-device polling across hosted stalls | Contract and lifecycle integration tested |
| 2.0.2 | 0.20.x | Same as 2.0.1; bounded retry for hosted tenant cold starts | Contract and lifecycle integration tested |
| 2.0.1 | 0.20.x | Same as 2.0.0; complete email authorization URL in agent/headless prompts | Contract and lifecycle integration tested |
| 2.0.0 | 0.20.x | `stream-v2`, `entity-wiki-v1`, `entity-quality-v2`, hosted device authorization | Contract and lifecycle integration tested |
| 1.4.1 | 0.18.2 | Imported immutable historical release | Historical compatibility record only |
| 0.3.x | 0.21.x | contract v1 capabilities, device authorization, memory turn-context/search/expand/evidence, session completion | Released |

Plugin 2.0.x uses the current 0.20 user-plugin discovery path and native `post_setup` hook.
Older Hermes lifecycle conventions are not supported by this release.
The `substrate` plugin installs with
`hermes plugins install Substrate-memory/Substrate-memory-plugins/plugins/substrate --ref v0.3.0 --no-enable`,
runs RFC 8628 device onboarding by itself, and registers `memory_search`, `memory_expand`,
and `memory_evidence`. It never requires a pre-existing API key.

## Failure behavior

The plugin fails closed when the hosted origin, capabilities, credential custody, or response
contracts are invalid. It does not fall back to a local/self-hosted server, legacy history
transmission, or another memory provider. Expired or revoked credentials start repairable
hosted onboarding while durable events remain queued.
The plugin fails closed when the configured origin, capabilities, credential custody, or response
contracts are invalid. It does not fall back to a local/self-hosted server or another memory
provider. Expired or revoked credentials restart repairable device onboarding while durable
capture events remain queued.

## Versioning

- Plugin behavior follows semantic versioning.
- The hosted origin is fixed at `https://app.trysubstrate.co`.
- Releases are immutable Git tags (`v0.3.0`) with attested `substrate.zip` and `SHA256SUMS` assets.
- Breaking server behavior requires a new protocol/schema identifier.
- Installation activates `memory.provider: substrate_wiki`; there is no silent auto-update.
- Rollback preserves profile-local spool, checkpoints, consent state, and credential custody.
- Rollback preserves profile-local state and credential custody.
20 changes: 13 additions & 7 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

## Scope

This repository owns the Hermes `substrate_wiki` plugin, its local state machinery, build/installer tooling, tests, release artifacts, and user documentation. Server routes, persistence, deployment, and production data belong in `Substrate-memory/Substrate-v2`.
This repository owns the Hermes `substrate` retrieval plugin (`plugins/substrate`), its
device onboarding, session-completion capture, response validation, release builder,
tests, and user documentation. Server routes, persistence, deployment, and production
data belong in the Substrate server repository.

## Workflow

Expand All @@ -12,19 +15,22 @@ This repository owns the Hermes `substrate_wiki` plugin, its local state machine
4. Run:

```bash
python -m pip install -e '.[dev]'
pytest -q
python -m compileall -q src scripts
python scripts/verify_public_plugin_candidate.py --root . --layout destination
uv sync --frozen --extra dev
uv run --frozen --extra dev ruff check .
uv run --frozen --extra dev python -m pytest -q
python3 scripts/check_public_hygiene.py --root .
uv run --frozen --extra dev python scripts/build_release.py --check
```

5. Update `CHANGELOG.md` and compatibility/security docs when behavior changes.
6. Sign every commit with the [Developer Certificate of Origin 1.1](https://developercertificate.org/) by adding `Signed-off-by: Name <email>` (`git commit -s`). This repository uses DCO sign-off, not a contributor license agreement.
7. Open a PR. Every PR requires an adversarial review and passing CI.
7. Open a PR. Every PR requires passing CI.

## Compatibility

Do not claim a Hermes or server version based on import success alone. Provider discovery, lifecycle hooks, tool schemas, profile isolation, import service, configuration, replay, rollback, and failure behavior must all pass.
Do not claim a Hermes or server version based on import success alone. Hook registration,
tool schemas, profile isolation, onboarding, session capture, configuration, and failure
behavior must all pass.

Breaking server behavior requires a new protocol/schema identifier with concurrent old-version support. Never silently rewrite user configuration or state.

Expand Down
Loading
Loading