Skip to content

Annotation

This content is for the 0.6.3 version. Switch to the latest version for up-to-date documentation.

The Raindrop annotation interface provides structured metadata storage using Machine-Readable Name (MRN) objects for addressing. This system acts as a key-value store designed for application metadata with hierarchical organization and automatic versioning. You can use annotations as a breadcrumb system to leave small hints and context about implementation decisions, bug fixes, and other metadata. Future AI coding assistants examining the deployed application can discover and use these breadcrumbs to understand previous changes.

Annotations store arbitrary data up to 64MB per entry. They support multiple data types including strings, binary data, and structured objects. The MRN addressing system enables precise targeting of metadata to specific application components, modules, or individual items.

Creating

Annotations are automatically available in all Raindrop applications without additional configuration. Access through the env.annotation interface:

export default {
async fetch(request: Request, env: Env): Promise<Response> {
// Annotation interface available on env.annotation
const metadata = await env.annotation.get(mrn);
return new Response('OK');
}
};

Accessing

Use the annotation interface through environment bindings to store and retrieve metadata:

// Store debugging context for AI assistant
const debugMRN = {
module: 'auth',
item: 'login-handler',
key: 'fix-context'
};
await env.annotation.put(debugMRN, JSON.stringify({
issue: 'JWT token validation failing',
solution: 'Updated key rotation logic',
timestamp: new Date().toISOString()
}));
// Retrieve context later
const context = await env.annotation.get(debugMRN);
if (context) {
const data = JSON.parse(await context.text());
console.log(`Previous fix: ${data.solution}`);
}

Core Concepts

Main Interfaces

  • get() - Retrieve annotation data by MRN
  • put() - Store annotation with automatic revision management
  • list() - Query annotations with prefix filtering

MRN Object Structure

Machine-Readable Name objects provide hierarchical addressing for annotations:

// Complete MRN with all optional fields
const fullMRN: MRNObject = {
type: 'annotation', // Resource type (annotation or label)
applicationName: 'my-app', // Application identifier
versionId: 'v1.0.0', // Version identifier
module: 'user-service', // Optional module name
item: 'auth-handler', // Optional item identifier
key: 'config', // Optional key name
revision: 'rev123' // Optional revision (read-only for get)
};

Bucket Object Body

Response object for retrieved annotations with data access methods:

// Annotation data wrapper with multiple access patterns
interface BucketObjectBody {
readonly key: string; // Storage key
readonly version: string; // Object version
readonly size: number; // Data size in bytes
readonly etag: string; // Entity tag
readonly uploaded: Date; // Upload timestamp
get body(): ReadableStream; // Raw data stream
text(): Promise<string>; // Text content
json<T>(): Promise<T>; // JSON parsed content
arrayBuffer(): Promise<ArrayBuffer>; // Binary content
blob(): Promise<Blob>; // Blob representation
}

System Limits

  • Maximum annotation size: 64MB per entry
  • Hierarchical addressing through MRN structure
  • Automatic revision management prevents conflicts

get

get(mrn: MRNObject): Promise<BucketObjectBody | null>

Example

Retrieve stored annotation metadata by MRN address:

const mrn = {
module: 'payment',
item: 'stripe-webhook',
key: 'error-patterns'
};
// Get annotation data
const annotation = await env.annotation.get(mrn);
if (annotation) {
const errorData = await annotation.json();
console.log(`Found ${errorData.patterns.length} error patterns`);
}

put

put(
mrn: MRNObject,
data: ReadableStream | ArrayBuffer | string | Blob | null,
options?: BucketPutOptions
): Promise<BucketObject>

Example

Store annotation data with automatic revision management:

const mrn = {
module: 'api',
item: 'rate-limiter',
key: 'optimization-notes'
};
// Store optimization context
const metadata = {
changes: 'Increased burst limit for premium users',
performance: '50ms avg response improvement',
date: new Date().toISOString()
};
const result = await env.annotation.put(mrn, JSON.stringify(metadata));
console.log(`Stored annotation: ${result.key} (${result.size} bytes)`);

list

list(options?: BucketListOptions): Promise<BucketObjects>

Example

Query annotations with prefix filtering for discovery:

// List all authentication-related annotations
const authAnnotations = await env.annotation.list({
prefix: 'annotation:my-app:v1.0.0:auth',
limit: 50
});
// Process results
for (const obj of authAnnotations.objects) {
console.log(`Found annotation: ${obj.key} (${obj.size} bytes)`);
}
// Handle pagination if needed
if (authAnnotations.truncated) {
const nextPage = await env.annotation.list({
prefix: 'annotation:my-app:v1.0.0:auth',
cursor: authAnnotations.cursor,
limit: 50
});
}