Clone this repository
For self-hosted knots, clone URLs may differ based on your setup.
Download tar.gz
- Switch from OAuth to simpler API key auth
- Add retry logic with exponential backoff
- Update examples and test coverage
- Remove httpx dependency (use requests)
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace single KAGI_AGGREGATOR_DID with comma-separated
TRUSTED_AGGREGATOR_DIDS env var. Allows multiple aggregators
to bypass community authorization checks.
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Register API key management routes in main.go (was missing)
- Add metrics handler for monitoring API key service health
- Improve error handling and validation in handlers
- Refactor apikey_service for better token refresh flow
- Update aggregator repo with credential persistence
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add API key-based authentication allowing aggregators to post to communities
via bot-like behavior. This complements OAuth for programmatic access.
Key components:
- API key generation, validation, and revocation endpoints
- Encrypted OAuth token storage for session persistence
- DualAuthMiddleware supporting API keys alongside OAuth
- Database migrations for key storage with encryption at rest
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Extract external link embeds (title, description, thumb) from quoted posts
- Handle blocked quoted posts (#viewBlocked) with "This post is from a blocked account"
- Handle deleted quoted posts (#viewNotFound) with "This post has been deleted"
- Handle detached quoted posts (#viewDetached) with "This post is unavailable"
- Add Detached boolean field for consistency with Blocked/NotFound pattern
- Add logging for JSON unmarshal failures and timestamp parsing errors
- Improve doc comments for embed extraction functions
Also adds beads issue Coves-327 for Phase 3: image/video extraction
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The Indigo xrpc client always sends Auth.AccessJwt as the Authorization
header, but com.atproto.server.refreshSession requires the refresh token
in that header. This was causing "InvalidToken: Invalid token type" errors
when community tokens needed refreshing.
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When embedding Bluesky posts that contain external links (link cards),
the external link metadata (URI, title, description, thumbnail) is now
extracted and stored in the BlueskyPostResult.
Changes:
- Add ExternalEmbed type to capture link card data
- Add Embed field to BlueskyPostResult
- Parse app.bsky.embed.external#view from Bluesky API responses
- Add unit tests for external embed extraction
- Fix productionPLCIdentityResolver to require db parameter
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Server was using local PLC directory (localhost:3002) for resolving real
Bluesky handles like "bretton.dev", which failed with 404 errors. Now uses
a dedicated production PLC resolver (https://plc.directory) that is READ-ONLY
for looking up existing Bluesky identities.
- Add productionPLCResolver in main.go for Bluesky handle resolution
- Update tests to use production PLC helper function
- Clean up debug logging in post service
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Address PR review feedback:
- Add debug logging when URI is not a string type
- Differentiate timeout errors from other parse errors
- Include unavailable post message in log output
- Add test case for wrong URI type (int instead of string)
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When a user pastes a Bluesky URL (bsky.app) as an external embed,
convert it to a social.coves.embed.post with proper strongRef
containing both URI and CID. This enables rich embedded quote posts
instead of plain external links.
Key changes:
- Implement tryConvertBlueskyURLToPostEmbed in service.go
- Detect Bluesky URLs and resolve them via blueskyService
- Parse URL to AT-URI (resolves handle to DID if needed)
- Fetch CID from Bluesky API for strongRef
- Fall back to external embed on errors (graceful degradation)
- Differentiated logging for circuit breaker vs other errors
- Keep unavailable posts as external embeds (no fake CIDs)
Test coverage:
- Unit tests for all error cases and success path
- Integration test for URL to strongRef conversion
Closes: Coves-p44
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Hot ranking formula now uses (score + 1) instead of score to prevent
new posts with 0 votes from sinking to the bottom. Previously,
0 / time_decay = 0 caused all unvoted posts to have rank 0.
Affects discover, timeline, and community feed repos.
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>