AISOURCEOFTRUTH.COM
OPENSPEC PLAN · FOR YOUR CODING AGENT

Proof that a work existed by a date

Your agent writes these files into openspec/changes/integrate-aisot-dated-works/ in your repo, runs openspec validate integrate-aisot-dated-works, and works the task list. The setup guide explains each step for people.

language: http · python · typescript   with: none fits this use case

OPENSPEC/CHANGES/INTEGRATE-AISOT-DATED-WORKS/PROPOSAL.MD
# Proposal: Proof that a work existed by a date

## Why
In a dispute over who had a work first, a file's own dates are easy to fake. A record fixes that this exact work existed by its logged time, signed by you, and the daily root carries outside timestamps that do not depend on the registry.

## What Changes
- Hash each finished piece and publish a provenance record.
- Use `lineage` to show drafts and what fed what.
- Export a bundle with proofs and timestamps when you need to show it.


## Capabilities
### New Capabilities
- `dated-works`: A signed, dated record per piece, with outside timestamps on the daily root.

## Impact
- External service: AI Source of Truth at https://aisourceoftruth.com. Reads are anonymous. Writes need a publisher key pair you generate, a client id and secret from registration, and a token from `/oauth/token`.
- Routes used: `POST /v1/records`, `GET /r/{digest}/certificate`, `POST /v1/export`.
- No PromptReports product is required.
- Source of this plan: https://aisourceoftruth.com/use-cases/proof-of-authorship (CC0). Regenerate it with `curl -H 'Accept: application/json' 'https://aisourceoftruth.com/use-cases/proof-of-authorship/openspec?lang=typescript'`.
OPENSPEC/CHANGES/INTEGRATE-AISOT-DATED-WORKS/DESIGN.MD
# Design: Proof that a work existed by a date

## Context
Writers, artists, researchers and studios. In a dispute over who had a work first, a file's own dates are easy to fake. A record fixes that this exact work existed by its logged time, signed by you, and the daily root carries outside timestamps that do not depend on the registry.

## Where it sits in your agent
Add it to the step where a piece is marked final, such as an export or a release script.

Over MCP, point the agent at `https://aisourceoftruth.com/mcp` (Streamable HTTP, JSON-RPC 2.0; read tools need no token). The tools this change uses: `publish_record`, `get_certificate`, `export_bundle`.

## Decisions
- Treat the registry as a source of facts about records, never about the world. Show what it says, with the digest, and do not turn a verdict into a quality score.
- If the registry cannot be reached, treat the answer as unknown (the same as `check`), never as `rely`, and retry later.
- Keep content private: send hashes. Never put personal data in a record; it is public and permanent.
- Keep the private key and client secret in your secret store. Rotate keys at `POST /v1/keys`; a revoked key cannot sign.

## Setup and signing helper

```ts
// Node 20 or later: WebCrypto signs Ed25519 with no dependency.
const AISOT = process.env.AISOT_ORIGIN ?? "https://aisourceoftruth.com";
const key = await crypto.subtle.importKey("jwk", JSON.parse(process.env.AISOT_PRIVATE_JWK!), { name: "Ed25519" }, false, ["sign"]);

async function token(): Promise<string> {
  const r = await fetch(`${AISOT}/oauth/token`, {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify({ grant_type: "client_credentials", client_id: process.env.AISOT_CLIENT_ID, client_secret: process.env.AISOT_CLIENT_SECRET }),
  });
  if (!r.ok) throw new Error(`token: ${r.status}`);
  return (await r.json()).access_token; // lasts 60 minutes
}

async function signedPost(path: string, body: unknown, contentType = "application/json"): Promise<any> {
  const raw = new TextEncoder().encode(JSON.stringify(body));
  const sig = Buffer.from(await crypto.subtle.sign("Ed25519", key, raw)).toString("base64url");
  const r = await fetch(`${AISOT}${path}`, {
    method: "POST",
    headers: {
      "content-type": contentType,
      authorization: `Bearer ${await token()}`,
      "x-aisot-key-id": process.env.AISOT_KEY_ID!,
      "x-aisot-signature": sig,
      "idempotency-key": crypto.randomUUID(),
    },
    body: raw,
  });
  if (!r.ok) throw new Error(`${path}: ${r.status} ${await r.text()}`);
  return r.json();
}
```

## Calls
### POST /v1/records
append a signed record; the answer carries its digest and inclusion proof.

```ts
const answer = await signedPost("/v1/records", record, "application/vnd.aisot.record+json");
```

### GET /r/{digest}/certificate
what the record proves, with signer, log position, proof and timestamps.

```ts
const answer = await (await fetch(`${AISOT}/r/{digest}/certificate`, { headers: { accept: "application/json" } })).json();
```

### POST /v1/export
an offline bundle with proofs and timestamps for up to 100 records.

```ts
const answer = await (await fetch(`${AISOT}/v1/export`, {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({"digests":["{digest}"]}),
})).json();
```

## What this does not prove
- A record proves this exact work existed by its recorded time and who signed it. It does not prove who wrote it, so it is evidence for a claim, not a verdict.
OPENSPEC/CHANGES/INTEGRATE-AISOT-DATED-WORKS/TASKS.MD
# Tasks: Proof that a work existed by a date

## 1. Configure
- [ ] 1.1 Set `AISOT_ORIGIN=https://aisourceoftruth.com` in the agent's environment.
- [ ] 1.2 Generate an Ed25519 key pair, register the publisher (`POST /v1/publishers`), and store `AISOT_CLIENT_ID`, `AISOT_CLIENT_SECRET`, `AISOT_KEY_ID` and the private key as secrets.
- [ ] 1.3 Mint a token at `/oauth/token` and confirm `GET /v1/me` answers with your publisher id.
- [ ] 1.4 Optional: add the MCP server `https://aisourceoftruth.com/mcp` to the agent's MCP config.

## 2. Build
- [ ] 2.1 Publish when finished: Hash the final file and publish a provenance record. Keep the original file safe: the record holds only its hash. (`POST /v1/records`)
- [ ] 2.2 Read the certificate: The certificate lists the appended time, the inclusion proof and the daily root's RFC 3161 timestamps and Bitcoin anchor once they exist. (`GET /r/{digest}/certificate`)
- [ ] 2.3 Export for a dispute: Export a bundle and give it with the file. Anyone can check it offline. (`POST /v1/export`)

## 3. Verify against the live registry
- [ ] 3.1 Publish when finished: The record's asset digest matches your file.
- [ ] 3.2 Read the certificate: The certificate shows the proof, or when it will be ready.
- [ ] 3.3 Export for a dispute: `node verify.mjs bundle.json` passes.

## 4. Done when
- [ ] 4.1 Each finished work has a dated, signed record and an offline bundle.
OPENSPEC/CHANGES/INTEGRATE-AISOT-DATED-WORKS/SPECS/DATED-WORKS/SPEC.MD
# dated-works Specification

## ADDED Requirements

### Requirement: Finished works are recorded
The release step SHALL publish a provenance record for each finished work and SHALL keep the exported bundle with the original file.

#### Scenario: Release
- **WHEN** a work is released
- **THEN** its record exists and a bundle for it is stored
$ curl -H 'Accept: application/json' https://aisourceoftruth.com/use-cases/proof-of-authorship/openspec?lang=typescript # this page is a rendering of the API. Reproduce it as data.