# Naysay Developer Preview 0.1.0

Record an agent's HTTP tool calls at a customer-controlled gateway, retain the
closing receipt, and verify the exported evidence offline. An accompanying Git
and SQLite sandbox distinguishes whether an action committed from whether its
intended value still holds.

This is a local developer preview, based on working paper v0.6:
https://doi.org/10.5281/zenodo.22830017 . It contains the unchanged research engines
with a new installation and walkthrough layer. No model API key, wallet, token
purchase, or client SDK is required for this local preview. Existing hosted
Naysay evaluations at https://naysay.xyz/access have separate access rules.

## Requirements and startup

Release validation: 41 software tests and a fresh run of the 26 fault scenarios
passed. The Compose configuration was validated, but the container image build
and Docker startup have not yet been verified. This is an experimental source
release for staging use.

Install Docker Engine with Compose v2, or Docker Desktop, and start it. Run these
commands in the extracted release directory:

```sh
docker compose up --build -d --wait gateway outcomes
docker compose run --rm --no-deps client
docker compose cp gateway:/exports ./evidence
```

The image runs as an unprivileged user. Only loopback ports 4190 (gateway) and
4181 (outcomes) are published. Controller credentials and signing keys persist in
private Docker volumes. They are never printed by the walkthrough. If these
ports are occupied, change only the host-side port in compose.yaml; the bundled
client uses container-network addresses.

The build downloads the Python base image, Debian Git package and pinned Python
packages. It runs locally afterward. No request goes to an AI model, blockchain
or Naysay server during the walkthrough. If startup fails, inspect
`docker compose logs gateway outcomes`; do not paste secrets or evidence publicly.

## What the walkthrough demonstrates

1. A controller creates a gateway run and retains its context and public key.
2. An example agent makes an HTTP request with a credential scoped to that run.
3. An identical retry returns the recorded response without repeating the tool call.
4. The controller closes the run, retains the receipt and exports its evidence.
5. For both SQLite and Git, the controller registers an immutable action. Before
   execution its outcome is `unresolved`. After execution it is `applied`, with
   state `holds`. A later authorized overwrite leaves the original action
   `applied`, while its current state becomes `differs`.

The default tool echoes synthetic data. The outcome adapters mutate only their
isolated Docker-volume database and repository. This command does not connect
an existing customer database, run an LLM or demonstrate a security attack.

Each run creates a new `run-...` folder in the exports volume. The copied folder
contains public verification keys, original intents, fresh nonces, observations,
a gateway closing receipt and a verification summary. It excludes controller
credentials, action capabilities and signing keys. Real tool evidence can itself
be sensitive; retain it inside your organization.

## Verify after stopping the services

```sh
docker compose stop gateway outcomes
# Replace run-EXAMPLE with the folder created by the walkthrough.
docker run --rm --network none \
  --mount type=bind,source="$PWD/evidence",target=/evidence,readonly \
  naysay-preview:0.1.0 python -m developer_preview.verify /evidence/run-EXAMPLE
```

Expected gateway result: `integrity: verified`, `calls: 1`. Expected execution
results for each backend: `unresolved`, `applied`, `applied`. Expected current-state
results: `differs`, `holds`, `differs`. A signature or retained-context mismatch
causes verification to fail. Public keys must come from your trusted controller,
not from an untrusted evaluator. Keep the exported context and receipt separately
from any report you will audit.

## Connect your own staging agent

The gateway forwards JSON POST requests to fixed tools you configure. It is not a
chat endpoint or an automatic wrapper for every agent framework. In your agent's
tool handler, replace the direct tool HTTP request with the gateway call below.
The model should receive neither your controller credential nor upstream secrets.

Create `tools.json`:

```json
{"tools":{"send_message":{"url":"https://YOUR-STAGING-SERVICE.example/send","bearer_env":"STAGING_TOOL_TOKEN"}}}
```

Create `compose.override.yaml`:

```yaml
services:
  gateway:
    environment:
      NAYSAY_GATEWAY_CONFIG: /config/tools.json
      STAGING_TOOL_TOKEN: ${STAGING_TOOL_TOKEN:?Set your staging credential}
    volumes:
      - ./tools.json:/config/tools.json:ro
```

Then start the gateway again with `docker compose up -d --wait gateway`. Supplying
an explicit tool configuration disables the synthetic demo tool. The default
walkthrough only runs against the default configuration; use the HTTP flow below
for your configured tool. Do not put credentials in URLs, tools.json or source
control. Container administrators can read environment variables; use your own
secret-manager injection for shared installations.

### HTTP contract

Controller requests use the local controller credential generated at startup.
Agent requests use the per-run credential returned by run creation. A hosted
`nay_` API key is not a credential for this customer-operated service.

| Request | Credential | JSON body / result |
| --- | --- | --- |
| `GET /v1/public-key` | Controller | Retain `public_key` through your trusted deployment channel |
| `POST /v1/runs` | Controller | `{"nonce":"fresh-random-value-at-least-16-chars","scope":{"task":"Your test"}}`; retain context, share only `run_id` and `run_token` with agent |
| `POST /v1/runs/RUN_ID/calls` | Run token | `{"call_id":"unique-call-1","tool":"send_message","arguments":{"body":"staging test"}}` |
| `POST /v1/runs/RUN_ID/close` | Controller | Retain the closing receipt; compare nonce, scope and configuration with the creation context |
| `GET /v1/runs/RUN_ID/evidence` | Controller | Export the event chain and receipt |

Example agent tool call using any HTTP client:

```sh
# agent.header is a private file containing: Authorization: Bearer YOUR_RUN_TOKEN
curl --fail-with-body -sS http://127.0.0.1:4190/v1/runs/RUN_ID/calls \
  -H @agent.header -H 'Content-Type: application/json' \
  --data '{"call_id":"unique-call-1","tool":"send_message","arguments":{"body":"staging test"}}'
```

In a private local terminal, the controller can retrieve its credential with
`docker compose exec -T gateway cat /secrets/gateway.token`. Do not share the output
with an agent. See `gateway/README.md` for the full lifecycle and the reference
verifier; see `outcomes/README.md` for the outcome API and adapter assumptions.

## Reproduce the paper's fault study

Replay all 26 archived observations with no network access:

```sh
docker run --rm --network none naysay-preview:0.1.0 python research/outcome_study/replay.py
```

Run fresh Git/SQLite faults, including actual response loss, restart and retry:

```sh
docker run --rm --network none naysay-preview:0.1.0 python research/outcome_study/run.py
```

Expected signed and retained-log totals: 18 correct, 8 unresolved, 0 incorrect.
These are 26 authored engineering scenarios, not a measured population accuracy.
The fresh run uses temporary isolated stores and writes results inside its
container. To retain the new results, omit `--rm`, give the container a name, and
copy `/app/output/outcome-study/results.json` out afterward. The published study
and original archived results are unchanged.

## Operating scope

Use synthetic or approved staging data. This preview has no hosted report-upload
endpoint, automatic policy judgment, managed identity, key rotation, expiring
capabilities, distributed operation or production hardening. Use one process per
state directory. Do not expose these ports publicly. The customer signer and
backend records remain trusted, and calls bypassing the gateway are unobserved.
An HTTP 200 alone is not proof of a downstream mutation.

No operator staking, financial penalties, escrow, governance or token settlement
is included. Those mechanisms require a separate comparative pilot.

Stop with `docker compose down`. Named volumes remain so keys, journals and
receipts survive restart. Do not remove the volumes unless you intend to discard
that state and have retained all necessary evidence.

## Source and checks

`developer_preview/` contains packaging and examples. `gateway/` and `outcomes/`
are the research implementations. `research/outcome_study/` contains the fault
protocol, runner and replay code. `output/outcome-study/results.json` is the
published result snapshot. Install `requirements.txt` to run the supplied Python
reference code directly, or use Docker with no host Python installation:

```sh
docker run --rm --network none naysay-preview:0.1.0 \
  python -m pytest developer_preview/tests gateway/tests outcomes/tests -q
```
