This repository contains ATProto lexicon schemas for the Gainforest ecosystem.
lexicons/
app/
gainforest/
common/ # Shared definitions
organization/ # Organization-related schemas
observations/ # Observation records (fauna, flora, etc.)
predictions/ # Prediction records
com/
atproto/
repo/ # Standard ATProto references
pub/
leaflet/ # Leaflet document schemas
-
Install goat - The AT Protocol CLI tool:
# macOS brew install goat # Or build from source go install github.com/bluesky-social/goat@latest
-
Login to your ATProto account:
goat account login -u your-handle.bsky.social -p your-app-password
Use an app password, not your main password.
Each lexicon namespace requires a DNS TXT record to prove ownership. The record maps the namespace to your account's DID.
Find your DID:
goat resolve your-handle.bsky.socialAdd DNS TXT records for each NSID group (first 3 segments of the NSID):
| NSID Pattern | DNS Record | Value |
|---|---|---|
app.gainforest.common.* |
_lexicon.common.gainforest.app |
did=did:plc:xxxxx |
app.gainforest.organization.* |
_lexicon.organization.gainforest.app |
did=did:plc:xxxxx |
app.gainforest.organization.observations.* |
_lexicon.observations.organization.gainforest.app |
did=did:plc:xxxxx |
app.gainforest.organization.predictions.* |
_lexicon.predictions.organization.gainforest.app |
did=did:plc:xxxxx |
DNS Provider Notes:
- In most DNS providers, enter only the subdomain part (e.g.,
_lexicon.commonfor Namecheap) - The domain is reversed from the NSID (e.g.,
app.gainforest.common→common.gainforest.app) - DNS propagation can take 5-30 minutes
# Check if DNS records are configured correctly
goat lex check-dns
# Or check specific lexicons
goat lex check-dns lexicons/app/gainforest/You can also verify manually:
dig TXT _lexicon.organization.gainforest.app +short
# Should return: "did=did:plc:xxxxx"Before publishing, validate your lexicon schemas:
goat lex lint
# Or lint specific files
goat lex lint lexicons/app/gainforest/See which lexicons are new, modified, or already published:
goat lex statusStatus indicators:
🟢- New (not yet published)🟠- Already published (no changes)🟣- Updated (will be modified)
# Publish all lexicons
goat lex publish
# Publish specific namespace
goat lex publish lexicons/app/gainforest/
# Skip DNS check (if DNS is configured but not yet propagated)
goat lex publish --skip-dns-check
# Update existing lexicons
goat lex publish --updatePublish indicators:
🟢- Successfully published (new)🟣- Successfully updated🟠- Skipped (already exists, use--updateto modify)⭕- Skipped (DNS not configured for this namespace)
After publishing, verify your lexicons are accessible:
# List all lexicon schemas in your account
goat ls -c your-handle.bsky.social | grep lexicon
# Fetch a specific lexicon
goat get at://your-handle.bsky.social/com.atproto.lexicon.schema/app.gainforest.organization.info-
Create from template:
goat lex new record app.gainforest.myfeature.myrecord
-
Edit the generated file at
lexicons/app/gainforest/myfeature/myrecord.json -
Lint, check DNS, and publish as described above.
- record - Data stored in user repositories (most common)
- query - Read-only API endpoint
- procedure - Write API endpoint
- subscription - Real-time event stream