diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000..a5e70e9
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,189 @@
+# Agent Guidelines for Motr Enclave
+
+This document provides guidelines for AI coding agents working in this repository.
+
+## Project Overview
+
+Motr Enclave is an Extism WebAssembly plugin written in Go, compiled with Go 1.25+ for the `wasip1` target. It provides encrypted key storage for the Nebula wallet with an embedded SQLite database.
+
+## Build Commands
+
+```bash
+# Build WASM plugin (primary build command)
+make build
+
+# Build with debug symbols
+make build-debug
+
+# Build optimized (requires wasm-opt)
+make build-opt
+
+# Generate SQLC database code
+make generate
+
+# Full rebuild
+make clean && make generate && make build
+```
+
+## Test Commands
+
+```bash
+# Run all tests
+make test
+
+# Run tests with coverage
+make test-cover
+
+# Run a single test
+go test -v -run TestFunctionName ./...
+
+# Run tests in a specific package
+go test -v ./db/...
+
+# Test the compiled plugin with Extism CLI
+make test-plugin
+```
+
+## Lint and Format
+
+```bash
+# Run all linters
+make lint
+
+# Format code
+make fmt
+
+# Run go vet
+make vet
+
+# Run all checks (fmt, vet, lint, test)
+make verify
+```
+
+## Code Style Guidelines
+
+### Imports
+
+Order imports in three groups separated by blank lines:
+1. Standard library
+2. External dependencies
+3. Internal packages
+
+```go
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+
+ "github.com/extism/go-pdk"
+
+ "enclave/db"
+)
+```
+
+### Naming Conventions
+
+| Element | Convention | Example |
+|---------|------------|---------|
+| Exported types | PascalCase | `GenerateInput`, `QueryOutput` |
+| Unexported types | PascalCase | `FilterParams` (internal use ok) |
+| Struct fields | PascalCase | `CredentialID`, `ChainID` |
+| JSON tags | snake_case | `json:"credential_id"` |
+| Functions | camelCase for private, PascalCase for exported | `parseFilter`, `Generate` |
+| Constants | PascalCase or ALL_CAPS | `MaxRetries` |
+| Variables | camelCase | `credentialBytes`, `didDoc` |
+
+### Type Definitions
+
+Define input/output types for each exported function:
+
+```go
+type GenerateInput struct {
+ Credential string `json:"credential"`
+}
+
+type GenerateOutput struct {
+ DID string `json:"did"`
+ Database []byte `json:"database"`
+}
+```
+
+### Extism Plugin Functions
+
+Exported functions must:
+1. Use `//go:wasmexport` directive
+2. Return `int32` (0 = success, 1 = error)
+3. Use `pdk.InputJSON()` for input parsing
+4. Use `pdk.OutputJSON()` for output
+5. Use `pdk.SetError()` for error reporting
+6. Log with `pdk.Log()`
+
+```go
+//go:wasmexport functionName
+func functionName() int32 {
+ pdk.Log(pdk.LogInfo, "functionName: starting")
+
+ var input InputType
+ if err := pdk.InputJSON(&input); err != nil {
+ pdk.SetError(fmt.Errorf("functionName: failed to parse input: %w", err))
+ return 1
+ }
+
+ // ... implementation ...
+
+ if err := pdk.OutputJSON(output); err != nil {
+ pdk.SetError(fmt.Errorf("functionName: failed to output: %w", err))
+ return 1
+ }
+ return 0
+}
+```
+
+### Error Handling
+
+1. Wrap errors with context using `fmt.Errorf("context: %w", err)`
+2. Prefix error messages with function name
+3. Return early on errors
+4. Use `errors.New()` for static errors
+
+```go
+if err != nil {
+ pdk.SetError(fmt.Errorf("generate: failed to initialize: %w", err))
+ return 1
+}
+```
+
+### SQL Queries (SQLC)
+
+- Schema in `db/schema.sql`
+- Queries in `db/query.sql`
+- Use SQLC annotations: `-- name: QueryName :one|:many|:exec`
+- JSON columns use `json.RawMessage` type override
+
+### Comments
+
+- Only add comments for complex logic, security implications, or TODOs
+- Avoid obvious comments
+- Use `// TODO:` for planned implementations
+
+## File Structure
+
+```
+motr-enclave/
+├── main.go # Plugin entry point, exported functions
+├── db/
+│ ├── schema.sql # Database schema
+│ ├── query.sql # SQLC query definitions
+│ └── *.go # Generated SQLC code
+├── sqlc.yaml # SQLC configuration
+├── Makefile # Build commands
+└── go.mod # Go module
+```
+
+## Dependencies
+
+Install with `make deps`:
+- `sqlc` - Database code generation
+- `golangci-lint` - Linting
+- `gofumpt` - Formatting
+- Extism CLI - Plugin testing
diff --git a/build/enclave.wasm b/build/enclave.wasm
new file mode 100755
index 0000000..e27fb2f
Binary files /dev/null and b/build/enclave.wasm differ
diff --git a/example/index.html b/example/index.html
new file mode 100644
index 0000000..70b9eb3
--- /dev/null
+++ b/example/index.html
@@ -0,0 +1,168 @@
+
+
+
+
+
+ Motr Enclave Test
+
+
+
+ Motr Enclave Plugin Test
+
+
+
Plugin Status
+
Loading plugin...
+
+
+
+
+
generate()
+
Initialize database with WebAuthn credential
+
+
+
+
+
+
+
+
load()
+
Load database from serialized buffer
+
+
+
+
+
+
+
+
+
exec()
+
Execute action with GitHub-style filter syntax
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
query()
+
Resolve DID to document with resources
+
+
+
+
+
+
+
+
Console Log
+
+
+
+
+
+
+
diff --git a/example/test.js b/example/test.js
new file mode 100644
index 0000000..91126c3
--- /dev/null
+++ b/example/test.js
@@ -0,0 +1,198 @@
+import createPlugin from 'https://esm.sh/@extism/extism@1.0.0/dist/browser/mod.js';
+
+let plugin = null;
+let generatedDatabase = null;
+
+function log(message, type = 'info') {
+ const consoleLog = document.getElementById('consoleLog');
+ const timestamp = new Date().toISOString().split('T')[1].split('.')[0];
+ const prefix = type === 'error' ? '[ERROR]' : type === 'success' ? '[OK]' : '[INFO]';
+ consoleLog.textContent += `${timestamp} ${prefix} ${message}\n`;
+ consoleLog.scrollTop = consoleLog.scrollHeight;
+ console[type === 'error' ? 'error' : 'log'](message);
+}
+
+function setStatus(message, type) {
+ const status = document.getElementById('status');
+ status.textContent = message;
+ status.className = `status ${type}`;
+}
+
+function formatOutput(data) {
+ try {
+ if (typeof data === 'string') {
+ const parsed = JSON.parse(data);
+ return JSON.stringify(parsed, null, 2);
+ }
+ return JSON.stringify(data, null, 2);
+ } catch {
+ return String(data);
+ }
+}
+
+async function loadPlugin() {
+ setStatus('Loading plugin...', 'loading');
+ log('Loading enclave.wasm...');
+
+ try {
+ plugin = await createPlugin('../build/enclave.wasm', {
+ useWasi: true,
+ logger: console
+ });
+
+ setStatus('Plugin loaded successfully', 'success');
+ log('Plugin loaded successfully', 'success');
+ } catch (error) {
+ setStatus(`Failed to load plugin: ${error.message}`, 'error');
+ log(`Failed to load plugin: ${error.message}`, 'error');
+ }
+}
+
+async function testGenerate() {
+ if (!plugin) {
+ log('Plugin not loaded', 'error');
+ return;
+ }
+
+ const output = document.getElementById('generateOutput');
+ const credential = document.getElementById('credentialInput').value;
+
+ log(`Calling generate() with credential: ${credential.substring(0, 20)}...`);
+ output.textContent = 'Running...';
+
+ try {
+ const input = JSON.stringify({ credential });
+ const result = await plugin.call('generate', input);
+ const data = result.json();
+
+ output.textContent = formatOutput(data);
+ log(`generate() completed. DID: ${data.did}`, 'success');
+
+ if (data.database) {
+ generatedDatabase = data.database;
+ log('Database buffer stored for load() test');
+ }
+ } catch (error) {
+ output.textContent = `Error: ${error.message}`;
+ log(`generate() failed: ${error.message}`, 'error');
+ }
+}
+
+async function testLoad() {
+ if (!plugin) {
+ log('Plugin not loaded', 'error');
+ return;
+ }
+
+ const output = document.getElementById('loadOutput');
+ const databaseInput = document.getElementById('databaseInput').value;
+
+ if (!databaseInput) {
+ output.textContent = 'Error: Database buffer is required';
+ log('load() requires database buffer', 'error');
+ return;
+ }
+
+ log('Calling load()...');
+ output.textContent = 'Running...';
+
+ try {
+ const input = JSON.stringify({
+ database: Array.from(atob(databaseInput), c => c.charCodeAt(0))
+ });
+ const result = await plugin.call('load', input);
+ const data = result.json();
+
+ output.textContent = formatOutput(data);
+ log(`load() completed. Success: ${data.success}`, data.success ? 'success' : 'error');
+ } catch (error) {
+ output.textContent = `Error: ${error.message}`;
+ log(`load() failed: ${error.message}`, 'error');
+ }
+}
+
+function useGeneratedDb() {
+ if (generatedDatabase) {
+ const base64 = btoa(String.fromCharCode(...generatedDatabase));
+ document.getElementById('databaseInput').value = base64;
+ log('Populated database input with generated database');
+ } else {
+ log('No generated database available. Run generate() first.', 'error');
+ }
+}
+
+async function testExec() {
+ if (!plugin) {
+ log('Plugin not loaded', 'error');
+ return;
+ }
+
+ const output = document.getElementById('execOutput');
+ const filter = document.getElementById('filterInput').value;
+ const token = document.getElementById('tokenInput').value;
+
+ if (!filter) {
+ output.textContent = 'Error: Filter is required';
+ log('exec() requires filter', 'error');
+ return;
+ }
+
+ log(`Calling exec() with filter: ${filter}`);
+ output.textContent = 'Running...';
+
+ try {
+ const input = JSON.stringify({ filter, token: token || undefined });
+ const result = await plugin.call('exec', input);
+ const data = result.json();
+
+ output.textContent = formatOutput(data);
+ log(`exec() completed. Success: ${data.success}`, data.success ? 'success' : 'error');
+ } catch (error) {
+ output.textContent = `Error: ${error.message}`;
+ log(`exec() failed: ${error.message}`, 'error');
+ }
+}
+
+function setFilter(filter) {
+ document.getElementById('filterInput').value = filter;
+}
+
+async function testQuery() {
+ if (!plugin) {
+ log('Plugin not loaded', 'error');
+ return;
+ }
+
+ const output = document.getElementById('queryOutput');
+ const did = document.getElementById('didInput').value;
+
+ log(`Calling query() with DID: ${did || '(current)'}`);
+ output.textContent = 'Running...';
+
+ try {
+ const input = JSON.stringify({ did: did || '' });
+ const result = await plugin.call('query', input);
+ const data = result.json();
+
+ output.textContent = formatOutput(data);
+ log(`query() completed. DID: ${data.did}`, 'success');
+ } catch (error) {
+ output.textContent = `Error: ${error.message}`;
+ log(`query() failed: ${error.message}`, 'error');
+ }
+}
+
+function clearLog() {
+ document.getElementById('consoleLog').textContent = '';
+}
+
+window.loadPlugin = loadPlugin;
+window.testGenerate = testGenerate;
+window.testLoad = testLoad;
+window.useGeneratedDb = useGeneratedDb;
+window.testExec = testExec;
+window.setFilter = setFilter;
+window.testQuery = testQuery;
+window.clearLog = clearLog;
+
+loadPlugin();