Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
db65650
docs: design + ADRs for Claude Code workflow promotion
pdettori Sep 2, 2026
f13a830
feat(config-bundle): deterministic USTAR writer, reader and digest
pdettori Sep 2, 2026
2920cfe
feat(config-bundle): resolve skills across scopes with cache/marketpl…
pdettori Sep 2, 2026
8be16bd
fix(config-bundle): use lstatSync to skip symlinks, strip quotes from…
pdettori Sep 2, 2026
3afe725
fix(config-bundle): follow symlinks and break cycles by canonical path
pdettori Sep 3, 2026
c7fcbfd
feat(config-bundle): two-bucket compatibility classifier
pdettori Sep 3, 2026
f648b15
fix(config-bundle): address classifier code review findings
pdettori Sep 3, 2026
5b0f96e
fix(config-bundle): use bare skill names from SKILL.md frontmatter
pdettori Sep 3, 2026
c8d91ce
feat(config-bundle): blocking pattern-based secret scan
pdettori Sep 3, 2026
7a5bb3a
fix(config-bundle): rename secrets module out of a .gitignore trap
pdettori Sep 3, 2026
7304385
feat(config-bundle): generated lockfile and injected prompt notes
pdettori Sep 3, 2026
43b1afa
fix(config-bundle): total-order comparators and sorting test coverage
pdettori Sep 3, 2026
940842d
feat(config-bundle): preflight checks with an explicit limits statement
pdettori Sep 3, 2026
5f4d5ce
fix(preflight): tighten extension matching and support markdown memor…
pdettori Sep 3, 2026
5fc6fce
fix(preflight): skip non-local memory links to avoid spurious warnings
pdettori Sep 3, 2026
782e30d
docs: amend the promotion design from implementation findings
pdettori Sep 3, 2026
505f079
feat(config-bundle): buildBundle orchestration
pdettori Sep 3, 2026
15f5012
fix(config-bundle): narrow checkSiblingPaths to owned dirs, warn not …
pdettori Sep 3, 2026
92fc156
fix(config-bundle): register and check every ancestor dir, not just leaf
pdettori Sep 3, 2026
a2c64b9
docs: preflight blocks on facts only, plus a sandbox-first workflow s…
pdettori Sep 3, 2026
0a25c9e
feat(harness): content-addressed Redis bundle store
pdettori Sep 3, 2026
a85e6e8
fix(harness/config-store): validate digest on write, refresh TTL on s…
pdettori Sep 3, 2026
9087814
feat(harness): resolve a promoted bundle into loader options
pdettori Sep 3, 2026
be806e9
fix(harness): make the fragment-ordering test able to fail, add escap…
pdettori Sep 3, 2026
833b663
feat(harness): mirror the bundle into the sandbox
pdettori Sep 3, 2026
7e1716d
fix(harness): sandbox overlay error handling and race documentation
pdettori Sep 3, 2026
51551f3
feat(harness): accept a promoted config in executeTurn
pdettori Sep 3, 2026
ea88404
feat(harness): resolve configRef on a prompt leaf
pdettori Sep 3, 2026
efef332
fix(harness): close bundle-redis race, start heartbeat before overlay
pdettori Sep 3, 2026
0f66a32
feat(harness): sh promote CLI
pdettori Sep 3, 2026
28947b7
fix(harness): promote CLI defects from review
pdettori Sep 3, 2026
24ff59a
docs(promote): pin the .git boundary contract and the slug's inherite…
pdettori Sep 3, 2026
d27d487
feat(deploy): sandbox binary inventory with shape and drift checks
pdettori Sep 3, 2026
c261350
fix(promote): resolve the shipped sandbox inventory relative to the h…
pdettori Sep 3, 2026
970c439
test(harness): end-to-end promoted-workflow smoke, plus docs and status
pdettori Sep 3, 2026
f7324d0
fix(deploy): make the drift check able to fail, and name the inventor…
pdettori Sep 3, 2026
2a5656c
fix(promote): bundle the intended --project dir, not process.cwd()
pdettori Sep 3, 2026
aaf4221
fix(harness): teach the sandbox notes/overlay path env vars, then tea…
pdettori Sep 3, 2026
8ab8c01
docs(adr-0031): correct the secret scan's protection claim
pdettori Sep 3, 2026
51ee6c1
fix(config-bundle): make the skills-root note degrade out loud when n…
pdettori Sep 3, 2026
f50c1b1
fix(config-bundle): bound the memory-link regexes, which were quadrat…
pdettori Sep 3, 2026
c46eacc
fix(config-bundle): bound skill symlink walk to its own canonical root
pdettori Sep 3, 2026
fa0a64e
fix(config-bundle): remove stale best-map entry on dedupe override
pdettori Sep 3, 2026
37728d2
fix(config-bundle): use replaceAll in digestDirName, not replace
pdettori Sep 3, 2026
eb3005d
fix(config-bundle): add shared digest validator, wire into both cache…
pdettori Sep 3, 2026
0639223
fix(config-bundle): warn instead of silently dropping namespaced prompts
pdettori Sep 3, 2026
97e5c30
docs: fix every reference to the nonexistent 'sh promote' command
pdettori Sep 3, 2026
b7b9845
fix(deploy): fail verify-sandbox-inventory.sh on unparseable inventory
pdettori Sep 3, 2026
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
10 changes: 10 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,16 @@ jobs:
- name: Run deploy shell tests
run: make test-deploy

- name: Verify sandbox inventory against the image
run: |
jq --version
IMAGE=ghcr.io/rossoctl/serverless-harness-sandbox:latest
docker pull "$IMAGE" || {
echo "::warning title=Sandbox inventory drift check skipped::could not pull $IMAGE; inventory drift is UNVERIFIED"
exit 0
}
bash deploy/knative/verify-sandbox-inventory.sh "$IMAGE"

proto:
runs-on: ubuntu-latest
timeout-minutes: 10
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ typecheck:
cd harness && pnpm exec tsc --noEmit
cd packages/k8s-sandbox && pnpm exec tsc --noEmit
cd packages/knative-server && pnpm exec tsc --noEmit
cd packages/config-bundle && pnpm exec tsc --noEmit
cd experiments && pnpm exec tsc --noEmit

# Laptop showcase: harness on kind, remote worker as a host container dialing out.
Expand Down
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ flowchart LR
`RuntimeDefault` seccomp, no service-account token automount.
- **Built on Pi** — wraps a pinned [`kagenti/pi`](https://github.com/kagenti/pi) coding agent through
an injectable `SessionStorageBackend` seam; the agent itself is unmodified.
- **Promote a local Claude Code workflow** — `cd harness && pnpm promote` bundles skills, `CLAUDE.md`,
memory, and a slash command from your local `~/.claude` into a content-addressed bundle a leaf can
dispatch by digest (see [Promoting a local Claude Code workflow](#promoting-a-local-claude-code-workflow)).

---

Expand Down Expand Up @@ -178,6 +181,41 @@ troubleshooting — is in **[`deploy/knative/README-ocp.md`](deploy/knative/READ

---

### Promoting a local Claude Code workflow

Iterate on a workflow locally in Claude Code — skills, `CLAUDE.md`, memory, a slash command —
then promote it:

```bash
cd harness && pnpm promote --entry my-workflow --project /path/to/your/project
```

`promote` reads the workflow — skills, `CLAUDE.md` chain, and memory — from `--project`, so
running it from the harness checkout without `--project` promotes the harness's own
configuration, not yours.

`promote` dedupes and classifies your local configuration, drops what cannot work in the harness
(with a reason for each), and scans for credentials before uploading. The scan has two tiers: a
structural match on a known key shape (an AWS access key, a PEM private-key block, a GitHub or
Slack token, an OpenAI-style key) **refuses the upload** and exits non-zero; a weaker prose
heuristic (`token: <value>`-shaped lines) only **warns and proceeds**, leaving the judgement to
you — that heuristic matches code and documentation placeholders too often to block on safely. It
writes a committable `.claude/promoted.lock.json` and uploads a content-addressed bundle; an
unchanged re-promotion uploads nothing.

Dispatch it by adding one field to any prompt leaf:

```json
{ "sessionId": "run-1/item-1", "kind": "prompt", "prompt": "…", "configRef": "sha256:…" }
```

Memory travels **read-only** — a promoted run consumes what you taught it locally and reports
discoveries back in the leaf result, which keeps leaf replay reproducible
([ADR-0031](docs/adrs/0031-promoted-memory-read-only.md)). MCP servers and subagents are not
promoted; see the [design](docs/specs/2026-09-02-claude-code-workflow-promotion-design.md) §2, §9.

---

## Dispatch Archetypes

The same backend serves three orchestration patterns, all validated end-to-end on Kind:
Expand Down
30 changes: 30 additions & 0 deletions deploy/knative/sandbox-inventory/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Sandbox binary inventories

Each file declares the commands one sandbox image provides. The promote CLI (`cd harness && pnpm promote`; see
[`../../../docs/specs/2026-09-02-claude-code-workflow-promotion-design.md`](../../../docs/specs/2026-09-02-claude-code-workflow-promotion-design.md) §4.5)
preflights a workflow's detected binaries against these **without cluster access**, so a
promotion can be checked on a laptop.

- **Filename** is the image ref with `:` and `/` replaced by `_`, plus `.json`.
- **Contract:** `{ "image": "<ref>", "binaries": ["<sorted, unique>"] }`.
- `tar`, `base64`, `flock` and `git` are required by `converge.ts` and `config-overlay.ts`.

Two checks guard these files, because they catch different failures:

| Check | Runs | Catches |
| --------------------------------- | ---------------------- | ---------------------------------------------------------------------- |
| `tests/sandbox-inventory.test.sh` | every PR, no cluster | malformed JSON, wrong filename, unsorted list, a missing required tool |
| `../verify-sandbox-inventory.sh` | where the image exists | **drift** — the file claiming something the image does not have |

A file that has drifted makes preflight lie, and a lying preflight is worse than none because
people stop checking it. Re-run the verify script whenever the sandbox Dockerfile changes.

## Provenance

`ghcr.io_rossoctl_serverless-harness-sandbox_latest.json` was generated from the real
published image, not curated by hand:

- Image: `ghcr.io/rossoctl/serverless-harness-sandbox:latest`
- Digest: `sha256:0683379d6368ab14c41d9bb46683178946091abba47b1832756d89f39afcdb9f`
- 347 binaries
- Enumerated 2026-09-03 by listing every executable on `PATH` inside the image
Loading
Loading