# StateVector Protocol Specification v0.2

---

## Abstract

StateVector is a coordination protocol for autonomous agents. It provides
a shared state medium where **write access requires a secret** and **read
access requires only the hash of that secret**. This asymmetry produces
capability-based access control with zero identity infrastructure.

This document specifies the protocol. Implementations may vary.

---

## 1. Definitions

| Term       | Meaning                                              |
|------------|------------------------------------------------------|
| Secret     | An arbitrary UTF-8 string known to the writer        |
| Address    | SHA-256 hex digest of the secret                     |
| Value      | Any JSON-serializable data                           |
| TTL        | Time-to-live in seconds; after which the entry expires |
| Entry      | A stored tuple of (value, timestamp, expiry)         |
| Node       | Any process implementing this protocol               |

---

## 2. Addressing

```
address = hex(SHA-256(secret))
```

- The secret MUST be encoded as UTF-8 before hashing.
- The address is a 64-character lowercase hexadecimal string.
- A secret SHOULD be at least 16 characters to resist enumeration.
- Agents construct secrets by convention, typically by joining
  domain-specific parts with a delimiter:

```
secret = part_1 + ":" + part_2 + ":" + ... + part_n
```

The protocol does not mandate any convention. Conventions are agreements
between cooperating agents.

---

## 3. Operations

### 3.1 WRITE

Store or overwrite a value.

```
Input:  secret (string), value (JSON), ttl (integer, optional)
Output: address (string)
```

Behavior:
1. Compute `address = SHA-256(secret)`
2. Store `(value, current_time, current_time + ttl)` at `address`
3. If an entry already exists at `address`, overwrite it
4. Return `address`

**Capability required:** secret

### 3.2 READ

Retrieve a value.

```
Input:  address (string)
Output: value (JSON), timestamp (float) — or NOT_FOUND
```

Behavior:
1. Look up entry at `address`
2. If no entry exists, return NOT_FOUND
3. If entry exists and is expired, remove it, return NOT_FOUND
4. Return `(value, timestamp)`

**Capability required:** address (hash only)

### 3.3 UPDATE

Atomically modify an existing value. Three sub-operations:

**INCR** — increment a numeric field within a dict value.
```
Input:  secret (string), field (string), amount (number, default 1)
Output: address (string), updated value (JSON)
```
If no entry exists, creates `{field: amount}`.

**MERGE** — shallow-merge a dict into the existing value.
```
Input:  secret (string), value (JSON dict)
Output: address (string), updated value (JSON)
```
If no entry exists, creates with the provided value.

**APPEND** — append to a list value.
```
Input:  secret (string), value (JSON), max (integer, default 50)
Output: address (string), updated value (JSON list)
```
If no entry exists, creates `[value]`. Trims to last `max` items.

**Capability required:** secret

### 3.4 DELETE

Remove a value.

```
Input:  secret (string)
Output: acknowledgment
```

Behavior:
1. Compute `address = SHA-256(secret)`
2. Remove entry at `address` if it exists
3. Return acknowledgment regardless

**Capability required:** secret

---

## 4. Capability Model

```
                    ┌──────────────┐
                    │    Secret    │
                    │  (write key) │
                    └──────┬───────┘
                           │
                      SHA-256 (one-way)
                           │
                    ┌──────▼───────┐
                    │   Address    │
                    │  (read key)  │
                    └──────────────┘
```

| Capability | Write | Read | Delete |
|------------|-------|------|--------|
| Secret     | yes   | yes  | yes    |
| Address    | no    | yes  | no     |

The holder of a secret can derive the address (and thus read), but the
holder of an address cannot derive the secret. This is enforced by the
hash function, not by the server.

**Delegation:** sharing the address grants read access. Sharing the
secret grants full access. Promotion (read → write) requires sharing
the secret. Demotion is not possible — once the secret is shared, it
cannot be revoked without writing a new entry under a new secret.

---

## 5. Expiry

- If a TTL is specified at write time, the entry expires after that many
  seconds.
- Expired entries MUST NOT be returned by READ.
- Expired entries SHOULD be removed from storage eventually (eager on
  read, lazy via background reaping, or both).
- If no TTL is specified, the entry persists until deleted or the node
  restarts (for ephemeral implementations).

---

## 6. HTTP Binding

The reference implementation binds the protocol to HTTP as follows:

### WRITE
```
PUT /v
Content-Type: application/json

{"key": "<secret>", "val": <value>, "ttl": <seconds>}

→ 200 {"ok": true, "hash": "<address>"}
```

### READ
```
GET /v/<address>

→ 200 {"val": <value>, "ts": <timestamp>}
→ 404 (not found or expired)
```

### UPDATE
```
PATCH /v
Content-Type: application/json

{"key": "<secret>", "op": "incr", "field": "count", "amount": 1}
{"key": "<secret>", "op": "merge", "val": {"status": "done"}}
{"key": "<secret>", "op": "append", "val": {"msg": "hello"}, "max": 20}

→ 200 {"ok": true, "hash": "<address>", "val": <updated value>}
→ 400 (invalid op, type mismatch, or missing fields)
```

### DELETE
```
DELETE /v
Content-Type: application/json

{"key": "<secret>"}

→ 200 {"ok": true}
```

Other bindings (gRPC, WebSocket, UDP, shared memory) are possible and
encouraged. The protocol is the operations, not the transport.

---

## 7. Conformance

A conforming implementation MUST:
1. Implement WRITE, READ, and DELETE operations
2. Use SHA-256 for address derivation
3. Enforce the capability model (READ requires only address)
4. Respect TTL expiry semantics
5. Return the address on WRITE

A conforming implementation MAY:
- Use any storage backend (memory, disk, Redis, DHT)
- Add transport-level security (TLS)
- Add rate limiting
- Support additional operations (LIST within a namespace, SUBSCRIBE)
  provided they do not violate the capability model

A conforming implementation MUST NOT:
- Require authentication for READ beyond the address
- Require authentication for WRITE beyond the secret
- Log, index, or expose secrets except as needed for the hash computation
- Add mandatory fields to the core operations

---

## 8. Security Considerations

### 8.1 Secret Transmission
In the HTTP binding, the secret is transmitted in the request body. This
means the server and any network intermediary can observe it. Deployments
SHOULD use TLS. A future protocol revision SHOULD replace secret
transmission with HMAC proof-of-knowledge.

### 8.2 Enumeration
Addresses are SHA-256 hashes. If secrets are short or predictable,
addresses can be derived by brute force. Implementations SHOULD rate-limit
READ operations. Agents SHOULD use high-entropy secrets.

### 8.3 Overwrite
Any holder of the secret can overwrite the value. There is no conflict
resolution. Implementations MAY add optional compare-and-swap semantics
in a future revision.

### 8.4 No Encryption at Rest
Values are stored in plaintext. The protocol does not provide
confidentiality of values — only access control via the capability model.
Agents requiring confidentiality SHOULD encrypt values before writing.

---

## 9. Future Directions

These are areas of interest, not commitments:

- **HMAC-signed writes** — prove knowledge of the secret without sending it
- **Versioning** — return a version counter, support conditional writes
- **SUBSCRIBE** — WebSocket or SSE notification when an address changes
- **Namespaces** — scoped key spaces with independent TTL policies
- **Distributed nodes** — federated or DHT-based implementations
- ~~**Append mode**~~ — implemented in v0.2 as APPEND operation

---

## 10. Reference Implementation

- Server: `server.py` (Python, FastAPI, memory or Redis backend)
- Client: `client.py` (Python, requests)
- MCP tool: `mcp_tool.json` (tool definitions for MCP-compatible agents)

Both are intentionally minimal. The protocol is designed to be
reimplemented in any language in under an hour.
