Anchor Providers
External anchor providers for the AgentOS provenance system. Extends the built-in signed hash chain with external tamper-evidence backends — WORM storage, transparency logs, and blockchain timestamping.
Proof Levels
Each provider advertises a proof level (ascending trust):
| Level | Meaning | Provider |
|---|---|---|
verifiable | Local signed hash chain only | Built-in (NoneProvider) |
externally-archived | Immutable external archive with retention policy | WormSnapshotProvider |
publicly-auditable | Append-only public transparency log | RekorProvider |
publicly-timestamped | Blockchain-anchored timestamp proof | OpenTimestampsProvider, EthereumProvider, SolanaProvider |
Installation
pnpm add @framers/agentos-ext-anchor-providers
Install the peer dependency for your chosen provider:
# For WORM Snapshot (S3 Object Lock)
pnpm add @aws-sdk/client-s3
# For Rekor (Sigstore Transparency Log)
pnpm add sigstore
# For OpenTimestamps (Bitcoin)
pnpm add opentimestamps
# For Ethereum (On-Chain Anchor)
pnpm add ethers
# For Solana (On-Chain Anchor)
pnpm add @solana/web3.js
# Optional (only if using base58 secret keys)
pnpm add bs58
Quick Start
Option 1: Config-Driven (via Registry)
Register all providers once at startup, then use the core factory:
import { registerExtensionProviders } from '@framers/agentos-ext-anchor-providers';
import { createAnchorProvider } from '@framers/agentos';
// Register once at startup
registerExtensionProviders();
// Create provider from config
const provider = createAnchorProvider({
type: 'rekor',
options: { serverUrl: 'https://rekor.sigstore.dev' },
});
Option 2: Direct Construction
Import and instantiate providers directly:
import { RekorProvider } from '@framers/agentos-ext-anchor-providers';
const provider = new RekorProvider({
serverUrl: 'https://rekor.sigstore.dev',
timeoutMs: 15000,
});
Using with AnchorManager
import { AnchorManager, profiles } from '@framers/agentos';
import { RekorProvider } from '@framers/agentos-ext-anchor-providers';
const provider = new RekorProvider();
const config = profiles.sealedAutonomous();
const anchorManager = new AnchorManager(
storageAdapter,
ledger,
keyManager,
config,
'', // table prefix
provider, // external anchor provider
);
Providers
WORM Snapshot Provider (S3 Object Lock)
Archives anchor records to S3 with Object Lock retention. Provides compliance-grade immutability — objects cannot be deleted or overwritten during the retention period.
Proof level: externally-archived
Peer dependency: @aws-sdk/client-s3
import { WormSnapshotProvider } from '@framers/agentos-ext-anchor-providers';
const provider = new WormSnapshotProvider({
bucket: 'my-provenance-bucket', // Required: S3 bucket with Object Lock enabled
region: 'us-east-1', // Required: AWS region
keyPrefix: 'provenance/anchors/', // Default: 'provenance/anchors/'
retentionDays: 365, // Default: 365
retentionMode: 'COMPLIANCE', // 'GOVERNANCE' (default) or 'COMPLIANCE'
timeoutMs: 30000, // Default: 30000
retries: 3, // Default: 3
});
Rekor Provider (Sigstore Transparency Log)
Publishes anchor hashes to Sigstore Rekor, a publicly auditable append-only transparency log. Entries are permanently recorded and anyone can verify inclusion.
Proof level: publicly-auditable
Peer dependency: sigstore
import { RekorProvider } from '@framers/agentos-ext-anchor-providers';
const provider = new RekorProvider({
serverUrl: 'https://rekor.sigstore.dev', // Default: public Rekor instance
timeoutMs: 30000,
retries: 3,
});
OpenTimestamps Provider (Bitcoin)
Creates OpenTimestamps proofs anchored to the Bitcoin blockchain. Proofs are initially pending and confirm after a Bitcoin block includes the calendar commitment (typically 1-2 hours).
Proof level: publicly-timestamped
Peer dependency: opentimestamps
import { OpenTimestampsProvider } from '@framers/agentos-ext-anchor-providers';
const provider = new OpenTimestampsProvider({
calendarUrls: [ // Default: public OTS calendars
'https://a.pool.opentimestamps.org',
'https://b.pool.opentimestamps.org',
'https://a.pool.eternitywall.com',
],
timeoutMs: 30000,
retries: 3,
});
Ethereum Provider (On-Chain Anchor)
Publishes anchor Merkle roots as calldata in Ethereum transactions. Provides cryptographic proof of existence at a specific block height.
Proof level: publicly-timestamped
Peer dependency: ethers
import { EthereumProvider } from '@framers/agentos-ext-anchor-providers';
const provider = new EthereumProvider({
rpcUrl: 'https://eth-mainnet.alchemyapi.io/v2/YOUR_KEY', // Required
signerPrivateKey: '0x...', // Required: hex private key
chainId: 1, // Default: 1 (mainnet)
contractAddress: '0x...', // Optional: anchor storage contract
gasLimit: 100000, // Optional: gas limit override
timeoutMs: 60000,
retries: 3,
});
Composite Usage
Use CompositeAnchorProvider from @framers/agentos to publish to multiple backends simultaneously:
import { CompositeAnchorProvider } from '@framers/agentos';
import { RekorProvider, WormSnapshotProvider } from '@framers/agentos-ext-anchor-providers';
const provider = new CompositeAnchorProvider([
new WormSnapshotProvider({ bucket: 'my-bucket', region: 'us-east-1' }),
new RekorProvider(),
]);
// Publishes to both WORM and Rekor in parallel
// Proof level: publicly-auditable (highest among children)
Or via config with the composite type:
registerExtensionProviders();
const provider = createAnchorProvider({
type: 'composite',
targets: [
{ type: 'worm-snapshot', options: { bucket: 'my-bucket', region: 'us-east-1' } },
{ type: 'rekor' },
],
});
Architecture
┌──────────────────────────────────────────────────────────────────┐
│ @framers/agentos (core) │
│ │
│ AnchorManager ──→ AnchorProvider interface │
│ │ ↑ │
│ │ ┌─────┴──────┐ │
│ │ │NoneProvider│ (built-in, local-only) │
│ │ └────────────┘ │
│ │ ┌──────────────────┐ │
│ │ │CompositeProvider │ (built-in, multi-target) │
│ │ └──────────────────┘ │
│ │ │
│ createAnchorProvider() ←─── registerAnchorProviderFactory() │
└──────────────────────┬───────────────────────────────────────────┘
│ (registry pattern)
┌──────────────────────▼───────────────────────────────────────────┐
│ @framers/agentos-ext-anchor-providers │
│ │
│ registerExtensionProviders() │
│ │ │
│ ├── WormSnapshotProvider (externally-archived) │
│ ├── RekorProvider (publicly-auditable) │
│ ├── OpenTimestampsProvider(publicly-timestamped) │
│ ├── EthereumProvider (publicly-timestamped) │
│ └── SolanaProvider (publicly-timestamped) │
└──────────────────────────────────────────────────────────────────┘
Writing Custom Providers
Implement the AnchorProvider interface from @framers/agentos:
import type { AnchorProvider, AnchorRecord, AnchorProviderResult, ProofLevel } from '@framers/agentos';
export class MyCustomProvider implements AnchorProvider {
readonly id = 'my-custom';
readonly name = 'My Custom Provider';
readonly proofLevel: ProofLevel = 'externally-archived';
async publish(anchor: AnchorRecord): Promise<AnchorProviderResult> {
try {
// Your publishing logic here
const ref = await publishToMyBackend(anchor);
return { providerId: this.id, success: true, externalRef: ref };
} catch (e) {
return { providerId: this.id, success: false, error: String(e) };
}
}
async verify(anchor: AnchorRecord): Promise<boolean> {
// Verify the anchor against the external record
return verifyAgainstMyBackend(anchor);
}
async dispose(): Promise<void> {
// Cleanup resources
}
}
Register it with the core factory:
import { registerAnchorProviderFactory } from '@framers/agentos';
import { MyCustomProvider } from './MyCustomProvider';
registerAnchorProviderFactory('my-custom', (opts) => new MyCustomProvider(opts));
Utilities
fetchWithRetry(url, init, options)
HTTP fetch wrapper with exponential backoff retry. Used internally by providers that communicate over HTTP.
import { fetchWithRetry } from '@framers/agentos-ext-anchor-providers';
const response = await fetchWithRetry('https://api.example.com/anchor', {
method: 'POST',
body: JSON.stringify(data),
}, { timeoutMs: 10000, retries: 3 });
canonicalizeAnchor(anchor)
Deterministic JSON serialization of an AnchorRecord with sorted keys. Ensures all providers hash the same byte representation.
hashCanonicalAnchor(anchor)
Computes SHA-256 hex digest of the canonical anchor representation.
Implementation Status
| Provider | Status | Notes |
|---|---|---|
| WormSnapshotProvider | Stub | Requires @aws-sdk/client-s3 implementation |
| RekorProvider | Stub | Requires sigstore SDK implementation |
| OpenTimestampsProvider | Stub | Requires opentimestamps implementation |
| EthereumProvider | Stub | Requires ethers implementation |
| SolanaProvider | Implemented | Requires @solana/web3.js (and a funded signer) |
All providers except SolanaProvider currently return { success: false } from publish() until their respective SDK integrations are implemented. SolanaProvider is functional when its optional peer dependencies are installed and the configured signer is funded.
Testing
# Run all tests
pnpm test
# Run with coverage
pnpm test:coverage
# Watch mode
pnpm test:watch
Test Structure
| File | Description |
|---|---|
test/providers.spec.ts | Unit tests for all 4 providers — identity, stub behavior, config |
test/register.spec.ts | Registration tests — verifies factories are registered with core |
test/integration.spec.ts | End-to-end integration — factory creation, provider identity, stub behavior |
test/utils.spec.ts | Utility tests — canonicalization, SHA-256 hashing, HTTP retry |
test/types.spec.ts | Config resolution tests — default values, overrides |
Related Packages
| Package | Description | Link |
|---|---|---|
@framers/agentos | Core AgentOS framework with AnchorProvider interface, AnchorManager, registry | packages/agentos |
@framers/agentos provenance types | AnchorProvider, ProofLevel, AnchorProviderResult interfaces | src/core/provenance/types.ts |
@framers/agentos factory | createAnchorProvider(), registerAnchorProviderFactory() | src/core/provenance/anchoring/providers/createAnchorProvider.ts |
@framers/agentos built-in providers | NoneProvider, CompositeAnchorProvider | src/core/provenance/anchoring/providers/ |
@framers/agentos AnchorManager | Periodic anchoring with external provider support | src/core/provenance/anchoring/AnchorManager.ts |
@framers/agentos profiles | sealedAuditable() convenience profile | src/core/provenance/config/PolicyProfiles.ts |
License
MIT