AI Attestation System Guide
AI Attestation System Guide
This guide explains how the automatic AI attestation system works for this blog, powered by attest.ink.
Overview
Every blog post automatically receives a cryptographic attestation that declares whether it was written by a human or with AI assistance. These attestations are:
- Generated automatically during Jekyll build
- Cryptographically signed with HMAC-SHA256
- Displayed as subtle badges on each post
- Verifiable by anyone through attest.ink
How It Works
1. Attribution in Front Matter
When creating a new post, add an attribution
field to your front matter:
---
layout: post
title: "Your Post Title"
date: 2025-01-15 10:00:00 -0500
categories: [tech, ai]
attribution: human
---
Attribution Options:
human
- Content written entirely by a humanai claude opus 4
- AI-assisted content using Claude 4 Opusai claude opus 3
- AI-assisted content using Claude 3 Opusai gpt 4
- AI-assisted content using GPT-4ai gpt 4.5
- AI-assisted content using GPT-4.5ai chatgpt 4.1
- AI-assisted content using ChatGPT- Any other AI model following the pattern:
ai [model-name]
If no attribution is specified, it defaults to ai claude opus 4
.
2. Automatic Attestation Generation
The attestation system works in two ways:
During Development (Local)
When you run bundle exec jekyll serve
or bundle exec jekyll build
, the Ruby plugin (_plugins/attest_hook.rb
) automatically:
- Detects new or modified posts
- Parses the attribution field
- Generates a cryptographic attestation
- Signs it with your configured key
- Saves it to
_data/attestations.json
Manual Generation
You can also manually regenerate all attestations:
node _scripts/generate-attestations.js
3. Attestation Display
Each post automatically displays:
- A subtle attestation badge in the footer
- The AI model used (if applicable)
- A “Verify Attestation” link
The main attestations page (/attestations/
) shows all blog attestations in one place.
Configuration
Signing Key Setup
The system uses HMAC-SHA256 signatures. To configure your signing key:
- Create
_config/signing.json
:{ "signing_key": "your-secret-signing-key-here", "signer_name": "Your Name", "signer_id": "your-id" }
-
Add
_config/signing.json
to.gitignore
(already done) - For production, set the environment variable:
export ATTEST_SIGNING_KEY="your-secret-signing-key-here"
GitHub Deployment
How It Works
The attestation system is designed to work seamlessly with GitHub Pages:
- Local Generation: Attestations are generated locally when you build the site
- Committed to Repository: The
_data/attestations.json
file is tracked in git - GitHub Actions: A workflow automatically regenerates attestations when posts change
- No Secrets Required: The default signing key works fine for public attestations
Existing GitHub Actions Workflow
This blog already includes .github/workflows/attest.yml
that:
- Triggers when posts are added or modified
- Runs
node _scripts/generate-attestations.js
- Commits updated attestations back to the repository
- Works automatically - no configuration needed!
Deployment Options
Option 1: GitHub Pages (Default) ✅
No additional setup required! Just push to GitHub and it works:
git add .
git commit -m "Add new post"
git push origin main
The GitHub Actions workflow will:
- Detect new/modified posts
- Generate attestations
- Commit them back
- GitHub Pages will rebuild with the new attestations
Option 2: Custom Signing Key (Optional)
For production sites that want unique signatures:
- Generate a strong signing key:
openssl rand -base64 32
- Add to GitHub Secrets:
- Go to Settings → Secrets and variables → Actions
- Add
ATTEST_SIGNING_KEY
with your key
- Update
.github/workflows/attest.yml
: ```yaml- name: Create attestations env: ATTEST_SIGNING_KEY: $ run: | node _scripts/generate-attestations.js ```
Deployment Checklist
_plugins/attest_hook.rb
is in the repository_scripts/generate-attestations.js
is in the repository_data/attestations.json
is tracked in git.github/workflows/attest.yml
workflow exists- Gemfile includes required gems (csv, base64, bigdecimal, logger, cgi)
- (Optional) Custom
ATTEST_SIGNING_KEY
secret in GitHub
Troubleshooting
Attestations not generating
- Check that the attribution field is properly formatted in your post’s front matter
- Look for errors in the Jekyll build output
- Manually run
node _scripts/generate-attestations.js
to see detailed errors
Verification failing
- Ensure the attestation URL isn’t corrupted (should be properly URL-encoded)
- Check that the model name matches one supported by attest.ink
- Verify the signature key hasn’t changed
Missing attestations after deployment
- Make sure
_data/attestations.json
is committed to git - Check GitHub Actions logs if using custom workflow
- Ensure the Ruby plugin is executing (check for “Attest:” messages in build logs)
Adding New AI Models
To add support for a new AI model:
- Update the model mapping in
_scripts/generate-attestations.js
:// In parseAttribution function else if (modelPart.includes('newmodel')) { return { type: 'ai', model: 'newmodel-1.0' }; }
- Update the same logic in
_plugins/attest_hook.rb
:# In parse_attribution method elsif model_part.include?('newmodel') return { type: 'ai', model: 'newmodel-1.0' }
Privacy & Security
- Content Privacy: Only content hashes are included, not the actual content
- Signing Key: Keep your signing key secret and never commit it
- Verification: Anyone can verify attestations without accessing your server
- Decentralized: Attestations work offline and don’t require any external services
Examples
Human-Written Post
---
attribution: human
---
Generates: Model: Human (no AI)
AI-Assisted Post
---
attribution: ai claude opus 4
---
Generates: Model: claude-4-opus • Role: assisted
No Attribution (Default)
---
# no attribution field
---
Generates: Model: claude-4-opus • Role: assisted
Support
For issues or questions:
- Check the attest.ink documentation
- Open an issue in this repository
- Visit the attest.ink GitHub