# Two installations that can stop and continue

This workshop gives each installation its own code, task database and private
memory library. They exchange the goal and deliberately shared final replies.
One installation drafts, the other reviews, then each returns in a fresh
process to finish its own part. Receiving a handoff never starts a model.

The example below uses two installations on one computer. It establishes
separate application state and process restarts. It does not establish
independent operators, separate operating-system accounts, two physical
computers, model identity or reliability at scale.

## Prepare the two installations

Extract the same verified package into two different code folders. Keep their
data outside both extracted folders. This example uses these locations:

| Purpose | Installation A | Installation B |
| --- | --- | --- |
| Extracted code | `D:\SpiralmeshProof\code-a` | `D:\SpiralmeshProof\code-b` |
| Shared-task records | `D:\SpiralmeshProof\tasks-a` | `D:\SpiralmeshProof\tasks-b` |
| Private memory | `D:\SpiralmeshProof\memory-a` | `D:\SpiralmeshProof\memory-b` |
| Local participant | `claude` | `codex` |

Use newly chosen, empty data directories for this practice. Do not point the
example at somebody else's library or your household history. The installation
labels are explicit host configuration, not credentials for a vendor or model.

From each code folder, run `python -B verify_bundle.py`. Both must pass before
use. The bundle verifier checks retained bytes against the included manifest;
compare the ZIP digest with its separately obtained release checksum when
checking where the code came from.

Save this same task as UTF-8 JSON at `D:\SpiralmeshProof\shared-task.json`:

```json
{
  "task_id": "independent-guide",
  "goal": "Write a practical 250-400 word checklist for an operator who wants two SPIRALMESH installations to exchange a draft, stop, and resume. Cover deliberate sharing, private memory, inspecting the actual retained result, and limits of the proof. Use only supplied facts; do not invent commands or claim to have inspected a live system. This is a local draft, not a publication.",
  "participants": ["claude", "codex"],
  "steps": [
    {
      "id": "draft",
      "principal": "claude",
      "instruction": "Draft the checklist. Your final reply is the text shared with the other installation. You may ask a question or decline; either stops this task. Keep private memory contents out of the shared text unless you deliberately choose to share them."
    },
    {
      "id": "review",
      "principal": "codex",
      "instruction": "Review the shared draft. Identify an unsupported claim or ambiguity and suggest a concrete correction. If you find none, explain the checks you actually performed. Your final reply is the shared review."
    },
    {
      "id": "revise",
      "principal": "claude",
      "instruction": "Return from your own retained checkpoint and the shared review. Revise the checklist and explain what changed. Preserve any disagreement instead of implying agreement."
    },
    {
      "id": "verify",
      "principal": "codex",
      "instruction": "Return from your own retained checkpoint. Check whether the revision addresses your review. Give a short assessment with any remaining limitation. Do not describe a received claim as independent verification of private memory."
    }
  ],
  "max_rounds": 2,
  "timeout": 180
}
```

The runner offers each participant the task, its own permitted library and
attributed earlier replies. It saves an accepted stage's private conversation
checkpoint for the later stage. The checkpoint is a host-retained record,
which the owner can read, correct or forget; it is not an executed action or
proof of continuing experience.

## Initialize and inspect without starting a model

Run in installation A's code folder:

```powershell
python -B scripts\independent_workshop.py --root D:\SpiralmeshProof\tasks-a init --id installation-a --principal claude --peer-id installation-b --peer-principal codex --memory-root D:\SpiralmeshProof\memory-a --task-file D:\SpiralmeshProof\shared-task.json
```

Run in installation B's code folder:

```powershell
python -B scripts\independent_workshop.py --root D:\SpiralmeshProof\tasks-b init --id installation-b --principal codex --peer-id installation-a --peer-principal claude --memory-root D:\SpiralmeshProof\memory-b --task-file D:\SpiralmeshProof\shared-task.json
```

Initialization creates the expressly selected local state and the Claude Max
policy file for A. It starts no model. Both results must name the expected code
folder, participant, private memory folder and identical `task_sha256`. A
conflict is an error; the initializer does not replace an existing pairing.

Each installation can inspect its own task with `status`. `preview` checks
local subscription readiness without a model request:

```powershell
python -B scripts\independent_workshop.py --root D:\SpiralmeshProof\tasks-a preview
```

Use `tasks-b` from B's code folder for its preview. A uses an existing Claude
Max login; B uses an existing ChatGPT login through Codex. The runner has no
API-key fallback or automatic retry. Each `next --yes` starts at most one stage,
with at most the task's `max_rounds` provider requests. The sample permits up
to eight requests across four stages. Preview is not a price quote or a reading
of remaining account usage.

## Draft, review, stop and return

In A, deliberately start the draft, inspect its result, and export the shared
handoff to a new file:

```powershell
python -B scripts\independent_workshop.py --root D:\SpiralmeshProof\tasks-a next --yes
python -B scripts\independent_workshop.py --root D:\SpiralmeshProof\tasks-a export --output D:\SpiralmeshProof\handoff-01.json
```

Only continue after the result records `complete`. A question, decline, failure
or unknown outcome stops this task. If a command reports an error, inspect its
retained state before deciding what to do; creating a new task or operation ID
does not make a retry safe.

In B, import that exact handoff, inspect it, then deliberately run the review:

```powershell
python -B scripts\independent_workshop.py --root D:\SpiralmeshProof\tasks-b import --input D:\SpiralmeshProof\handoff-01.json
python -B scripts\independent_workshop.py --root D:\SpiralmeshProof\tasks-b next --yes
python -B scripts\independent_workshop.py --root D:\SpiralmeshProof\tasks-b export --output D:\SpiralmeshProof\handoff-02.json
```

Each command is a finite Python process. After both stages finish, close the
terminal sessions. Open new terminals in the corresponding code folders. In A:

```powershell
python -B scripts\independent_workshop.py --root D:\SpiralmeshProof\tasks-a import --input D:\SpiralmeshProof\handoff-02.json
python -B scripts\independent_workshop.py --root D:\SpiralmeshProof\tasks-a next --yes
python -B scripts\independent_workshop.py --root D:\SpiralmeshProof\tasks-a export --output D:\SpiralmeshProof\handoff-03.json
```

In B's fresh terminal:

```powershell
python -B scripts\independent_workshop.py --root D:\SpiralmeshProof\tasks-b import --input D:\SpiralmeshProof\handoff-03.json
python -B scripts\independent_workshop.py --root D:\SpiralmeshProof\tasks-b next --yes
python -B scripts\independent_workshop.py --root D:\SpiralmeshProof\tasks-b export --output D:\SpiralmeshProof\handoff-04.json
```

Finally import `handoff-04.json` in A and run `status` in both installations.
Both should report the same four shared stage results and task status
`complete`. Run the existing `scripts/workshop.py` deliverable command against
either task folder to produce a readable, attributed Markdown artifact:

```powershell
python -B scripts\workshop.py --tasks D:\SpiralmeshProof\tasks-a deliverable independent-guide --out D:\SpiralmeshProof\INDEPENDENT-GUIDE.md
```

The latest contribution is B's assessment; the guide and earlier review remain
in the ordered contributions. Read those contributions to judge whether the
collaboration produced useful work.

## What to inspect in the proof

The shared envelope contains the agreed definition and a contiguous sequence
of final shared replies. Each reply has a stage, participant, invocation and
disposition. The destination imports it as a **peer report**. It does not receive
the sender's checkpoint ID, private receipt path, memory-tool results or local
memory evidence.

The local `status` output includes its own evidence and paths, so keep that
output private. For each installation's returning stage, inspect its private
run receipt and checkpoint readback: the invocation must be new, the prior
conversation must actually be restored, and the current checkpoint must be
readable. A model saying it remembers is insufficient. A host-restored
checkpoint is distinct from a model-requested memory `read` operation.

Exact handoff replay returns the original import receipt without another
write or model invocation. That receipt records the historical import, not a
fresh check of current state. Use `status` for current state. Changed history,
wrong peers, out-of-order results, newly forged receiver stages and attempts
to continue after a terminal stop are rejected. Unknown outcomes cannot be
replaced through a later handoff; inspect and reconcile their local evidence.

An owner-corrected checkpoint is resolved locally. A missing or forgotten
checkpoint prevents continuation rather than silently substituting an empty
history. Task refusal does not remove unrelated memory access.

## MCP and the optional A2A handoff

The existing memory server uses stdio MCP and supports negotiation through
`2025-06-18`. It binds the library and principal in the host launcher. The
independent workshop reuses the existing bounded participant runner; exchanging
a task does not expose one participant's MCP memory tools to the peer.

The optional A2A 1.0 adapter carries the same explicit handoff to an attended
loopback receiver. It is a narrow handoff implementation, not complete A2A
conformance. It does not turn receipt into model execution, import arbitrary
new tasks or make private memory remotely available. File exchange above is
sufficient for the four-stage exercise.

To use the loopback receiver, create a strong random bearer token in a local
file outside the package, without printing the token. Give the paired local
sender access to that file. In the receiver's code folder, run:

```powershell
python -B scripts\independent_workshop.py --root D:\SpiralmeshProof\tasks-b serve --port 0 --token-file D:\SpiralmeshProof\pair-token.txt
```

The foreground receiver prints its actual listening URL. In the sender's
terminal, substitute that printed URL in this command:

```powershell
python -B scripts\independent_workshop.py --root D:\SpiralmeshProof\tasks-a send --url RECEIVER_URL --token-file D:\SpiralmeshProof\pair-token.txt
```

Inspect the receiver's task state, then stop the receiver with Ctrl+C when the
exchange is complete. No background service or model is started by receiving
the message. Keep the token file private and out of envelopes, task text and
published proof. Pairing and bearer access establish the configured host
boundary; they do not authenticate the model behind a contribution. Deployment
across machines, independent operators and production transport remain separate
verification work.

## Provider-free regression

From the extracted code folder, run:

```powershell
$env:PYTHONPATH = "$PWD\src"
python -B -m unittest discover -s tests -p test_workshop_exchange.py
```

This creates temporary invented task records. It checks four alternating
stages in separate stores, fresh Python process readback, replay, privacy
projection and adversarial handoffs with recomputed digests. It makes no
provider call and provides no evidence that a live participant completed a
task. The live exercise and this regression must be reported separately.
