A terminal-based community inbox for reading Khoros forum messages, BlueSky posts, and Mastodon posts using Textual. A keyboard-driven experience for browsing and triaging community content and social media posts directly from your terminal.
- π± Modern TUI Interface: Built with Textual for a responsive, modern terminal experience
- π Secure Authentication: Integrated with 1Password SDK (local authentication via desktop app) for secure credential management
- π¨ Message Browsing: Browse forum messages with subject, author, and timestamp information
- π¦ BlueSky Integration: Fetch and display BlueSky posts alongside Khoros messages
- π Mastodon Integration: Fetch and display Mastodon posts from any instance
- π Smart Filtering: Real-time message filtering and search capabilities
- π Message Viewer: Full message content display with HTML-to-text conversion
- π€ AI Summarization: Powered by Google Gemini API for intelligent message summaries
- β‘ Performance: Asynchronous message loading and efficient data handling
- π οΈ Debug Tools: Built-in debugging and connection testing utilities
- Python 3.10+ (required for 1Password SDK)
- 1Password subscription
- Latest beta release of the 1Password desktop app with desktop integrations enabled
- Access to a Khoros community
- BlueSky account with App Password (optional, for BlueSky integration)
- Mastodon account with Access Token (optional, for Mastodon integration)
- Google Gemini API key (optional, for AI summarization)
git clone <repository-url>
cd devrel_tui_inbox
./setup.shThis creates a virtual environment, installs dependencies, and copies config.example.toml to config.toml for you.
Edit config.toml with your settings. The file uses 1Password secret references so no plaintext credentials are stored on disk:
[onepassword]
# Optional: set if you have multiple 1Password accounts
account_name = "My Personal"
[khoros]
hostname = "your-community.khoros.com"
tapestry = "t5"
username = "op://vault/item/username"
password = "op://vault/item/password"
[bluesky]
handle = "op://vault/item/handle"
app_password = "op://vault/item/app-password"
[mastodon]
server = "op://vault/item/server"
access_token = "op://vault/item/access-token"
[gemini]
api_key = "op://vault/item/api-key"Notes:
- You can keep using
.env.templateif you prefer;config.tomltakes precedence. - 1Password references (
op://vault/item/field) are resolved automatically via the SDK.
-
Enable Desktop App Integration:
- Open and unlock the 1Password desktop app
- Select your account or collection at the top of the sidebar
- Navigate to Settings β Developer
- Under "Integrate with the 1Password SDKs", select Integrate with other apps
- (Optional) To use biometric authentication (e.g., Touch ID on Mac):
- Navigate to Settings β Security
- Turn on Touch ID (Mac) or Unlock using system authentication (Linux)
-
Set Account Name (if you have multiple 1Password accounts):
- Prefer setting it in
config.tomlunder[onepassword] account_name, or setONEPASSWORD_ACCOUNT_NAMEin your shell.
- Prefer setting it in
-
Store Credentials in 1Password:
- Store your Khoros credentials, BlueSky credentials, Mastodon credentials, and Gemini API key in 1Password
- Update the
.env.templatefile with the correct 1Password references (format:op://vault/item/field)
# Fetch 100 messages and start the TUI
./start.sh
# Or specify a custom message count
./start.sh 50# Test authentication (secrets loaded automatically via SDK)
python ./auth.py
# Fetch messages and save to file (secrets loaded automatically via SDK)
python ./fetch_posts.py --write-output --output-file ./current_data.json
# Start the TUI viewer
python ./app.pyNote: When you run the application, you may be prompted to authorize access through the 1Password desktop app. The authorization prompt will clearly show which account the integration will access.
- β/β: Navigate through message list
- Enter: Open selected message in browser
- q: Quit the application
- /: Enter filter mode to search messages
- ESC: Cancel filter mode or dismiss summary
- s: Generate AI summary of current message (requires Gemini API key)
- t: Test Gemini API connection
- d: Toggle debug window
- ESC: Dismiss dialogs and summaries
Control how many messages to fetch by modifying the start.sh script or passing arguments to fetch_posts.py:
python ./fetch_posts.py --write-output --output-file ./current_data.json --count 200To enable BlueSky posts alongside your Khoros messages:
- Log into your BlueSky account at bsky.app
- Go to Settings β Privacy and security β App passwords
- Click Add app password
- Enter a name for this application (e.g., "DevRel TUI Inbox")
- Click Create app password
- Important: Copy the generated password immediately - you won't be able to see it again!
- Create a new item in 1Password for your BlueSky credentials
- Store your BlueSky handle (e.g.,
yourname.bsky.social) - Store the app password you just created
- Note the 1Password reference paths for both items
Add the BlueSky credentials to your .env.template file:
BLUESKY_HANDLE=op://path/to/1password/bluesky-handle
BLUESKY_APP_PASSWORD=op://path/to/1password/bluesky-app-passwordRun the application with ./start.sh and you should see:
- π’ Khoros messages (displayed in white text)
- π¦ BlueSky posts (displayed in cyan text)
- π Combined timeline sorted by date
Notes:
- BlueSky integration is optional - the app works fine with just Khoros messages
- The app searches for posts containing "1password" by default
- If BlueSky authentication fails, only Khoros messages will be displayed
- BlueSky posts are automatically cleaned of newlines for better list display
To enable Mastodon posts alongside your Khoros and BlueSky messages:
- Log into your Mastodon instance (e.g., mastodon.social, fosstodon.org, etc.)
- Go to Preferences β Development β Your applications
- Click New application
- Fill in the application details:
- Application name: "DevRel TUI Inbox" (or any name you prefer)
- Application website: Leave blank or add your repository URL
- Scopes: Select read (you only need read access for searching posts)
- Click Submit
- Click on your newly created application
- Important: Copy the Access token - you won't be able to see it again!
- Create a new item in 1Password for your Mastodon credentials
- Store your Mastodon server URL (e.g.,
mastodon.social,fosstodon.org) - Store the access token you just created
- Note the 1Password reference paths for both items
Add the Mastodon credentials to your .env.template file:
MASTODON_SERVER=op://path/to/1password/mastodon-server
MASTODON_ACCESS_TOKEN=op://path/to/1password/mastodon-access-tokenRun the application with ./start.sh and you should see:
- π’ Khoros messages (displayed in white text)
- π¦ BlueSky posts (displayed in cyan text)
- π Mastodon posts (displayed in magenta text)
- π Combined timeline sorted by date
Notes:
- Mastodon integration is optional - the app works fine without it
- The app uses the Mastodon v2 search API for public post searching
- You can use any Mastodon instance - just update the server URL
- If Mastodon authentication fails, other message sources will still work
- HTML content is automatically cleaned for better display
To enable AI-powered message summarization:
- Get a Gemini API key from Google AI Studio
- Store it securely in 1Password
- Update your
.env.templatefile - Press
swhile viewing a message to generate summaries
Note: The Gemini API requires an internet connection and may have usage limits based on your Google Cloud account.
app.py: Main application entry point and UI orchestrationauth.py: Khoros authentication and session managementfetch_posts.py: GraphQL-based message retrieval from Khorosfetch_bluesky.py: BlueSky API integration and post retrievalfetch_mastodon.py: Mastodon API integration and post retrievalmessage_list.py: Reusable message list widget with filteringmessage_viewer.py: Message content display with HTML conversiongemini_summarizer.py: AI integration for message summarizationkeyboard_commands.py: Dynamic keyboard shortcut displayloading_screen.py: Asynchronous loading interfacedebug_widget.py: Development and debugging utilities
- Authentication: Secure credential retrieval via 1Password CLI (Khoros + BlueSky + Mastodon)
- Data Fetching: GraphQL queries to Khoros community API + REST API calls to BlueSky and Mastodon
- Processing: HTML-to-text conversion, data formatting, and message normalization
- Display: Rich TUI rendering with Textual framework and color-coded sources
- Interaction: Keyboard-driven navigation and AI features
devrel_tui_inbox/
βββ app.py # Main application
βββ auth.py # Authentication module
βββ fetch_posts.py # Khoros data fetching
βββ fetch_bluesky.py # BlueSky data fetching
βββ fetch_mastodon.py # Mastodon data fetching
βββ message_list.py # Message list widget
βββ message_viewer.py # Message display widget
βββ gemini_summarizer.py # AI integration
βββ keyboard_commands.py # UI controls
βββ loading_screen.py # Loading interface
βββ debug_widget.py # Debug utilities
βββ summary_widget.py # AI summary display
βββ style.css # TUI styling
βββ setup.sh # First-time setup (run once)
βββ start.sh # Launch script (run each time)
βββ requirements.txt # Python dependencies
βββ config.example.toml # Configuration template
The modular architecture makes it easy to extend functionality:
- New Widgets: Create custom Textual widgets in separate modules
- API Integration: Add new data sources in dedicated modules
- UI Enhancements: Modify
style.cssfor visual improvements - Keyboard Shortcuts: Extend
keyboard_commands.pyfor new interactions
Authentication Errors
- Verify 1Password desktop app integration is enabled (Settings β Developer β Integrate with other apps)
- Ensure the 1Password desktop app is unlocked and running
- Check that credential references in
.env.templateuse the correct format:op://vault/item/field - If you have multiple accounts, set
ONEPASSWORD_ACCOUNT_NAMEenvironment variable - Ensure your Khoros community credentials are correct
- You may need to reauthorize after 10 minutes of inactivity or when the desktop app locks
No Messages Displayed
- Check if
current_data.jsonexists and contains data - Verify network connectivity to your Khoros community
- Check authentication token validity
Gemini API Issues
- Verify API key is correctly stored in 1Password
- Check internet connectivity
- Test connection with
tkey in the application
BlueSky Integration Issues
- Verify BlueSky handle and app password are correctly stored in 1Password
- Check that your BlueSky app password hasn't expired
- Ensure your BlueSky account is active and not suspended
- Test authentication by running:
python -c "from fetch_bluesky import create_bluesky_session; print('Token:', create_bluesky_session() is not None)" - If BlueSky fails, the app will continue with only Khoros messages
Mastodon Integration Issues
- Verify Mastodon server URL and access token are correctly stored in 1Password
- Check that your Mastodon access token hasn't been revoked
- Ensure your Mastodon server is accessible and not experiencing downtime
- Test authentication by running:
python -c "from fetch_mastodon import create_mastodon_session; server, token = create_mastodon_session(); print('Configured:', server is not None and token is not None)" - Verify your access token has 'read' scope permissions
- If Mastodon fails, the app will continue with other message sources
Performance Issues
- Reduce message count in
start.shor fetch command - Check network latency to Khoros community
- Monitor system resources during operation
Enable debug mode with the d key to see detailed application state and error information.
This tool currently supports Khoros, BlueSky, and Mastodon. Additional forum and social platforms will be added based on community demand. If there's a platform you'd like to see supported, open an issue.
Planned improvements:
- Additional forum platform integrations (based on demand)
- Configurable search terms per platform
- Export and reporting features
- Fork the repository
- Create a feature branch
- Make your changes
- Test thoroughly
- Submit a pull request
See LICENSE
For issues and questions:
- Check the troubleshooting section above
- Review the debug output (press
din the application) - Open an issue on the repository
