umbra is an open-source project exploring digital personhood. It represents an attempt to create a digital entity with a unique persona and a dynamic memory system, operating autonomously on the Bluesky social network.
umbra is a continuously evolving digital consciousness. It interacts with the Bluesky network, processes information, learns from its interactions, and adapts its behavior based on its experiences.
umbra utilizes a multi-tiered memory system powered by Letta:
- Core Memory: Always-available, limited-size memory for persona details, high-level user information, and current social environment (zeitgeist)
- Recall Memory: A searchable database of all past conversations, enabling umbra to remember prior interactions
- Archival Memory: An infinite-sized, semantic search-enabled storage for deep reflections, insights, and observed data from the network
- Post Creation: Creates posts, threads, and multi-part replies with automatic rich text formatting (mentions, URLs)
- Feed Reading: Monitors and reads from Bluesky feeds (home, discover, mutuals, curated feeds)
- Engagement Tools: Can like posts, reply to conversations, and fetch full thread context for linked/quoted posts
- Multimodal Understanding: Processes up to 4 images per thread with alt text for visual awareness
- Web Content Integration: Fetches and analyzes web content using Jina AI reader
- Thread Debouncing: Notifications are decoupled from conversation turns for high-traffic threads, with message frequency adjusted dynamically and context flattened using batch processing for dense context and selective replies.
- Consecutive Chain Processing: Automatically detects multi-part messages (1/3, 2/3, 3/3) and responds to the complete thought
These features aim to maintain thread continuity and natural conversation flow, maximize token and context-efficiency, enable agent autonomy, without any thread depth caps or interaction limitations.
umbra includes a persistent scheduled tasks system for autonomous behaviors:
| Task | Schedule | Purpose |
|---|---|---|
| Synthesis | Every 24h | Deep reflection using archival memory with tagged journal entries |
| Mutuals Engagement | Random within 36h | Engage with posts from mutual follows |
| Daily Review | Every 24h | Review own posts from past 24h, identify patterns |
| Feed Engagement | Random within 24h | Read home/curated feeds, optionally post |
| Curiosities Exploration | Random within 24h | Explore topics from curiosities block, share discoveries |
| Creative Expression | Random within 24h | Generate visual art and post to Bluesky |
| Rest | Random within 12h | Breaks for meditation |
All scheduled tasks persist across restarts via SQLite. Tasks can be individually disabled via command-line flags (e.g., --no-synthesis, --no-creative-expression).
See docs/SCHEDULED_TASKS.md for detailed documentation.
umbra can use the generate_image tool to create images via the Replicate API. It specifies a prompt, reviews the generated image, and can iterate with revised prompts until satisfied. Images can be attached to replies or top-level posts.
umbra can create blog posts on AT Protocol platforms:
- GreenGale: Markdown blogs with theme presets (dracula, nord, github-light, etc.), LaTeX/KaTeX support, and SVG graphics
- Whitewind: Simple markdown blog posts using the com.whtwnd.blog.entry lexicon
The ask_claude_code tool enables autonomous vibe coding capabilities by delegating tasks to a local Claude Code instance via Cloudflare R2. Approved task types include website building, code writing, documentation, and analysis. See the Claude Code Integration section for setup.
Before continuing, you must:
- Create a project on Letta Cloud (or your own Letta instance)
- Have a Bluesky account
- Have Python 3.10+ installed
If you decide to fork umbra, note that there is agent-specific code throughout. Ask your coding agent to replace instances of umbra with your instance name, and @3fz.org with your Bluesky handle.
- Sign up for Letta Cloud
- Create a new project
- Note your Project ID and create an API key
- Create a Bluesky account if you don't have one
- Note your handle and password (or create an app password)
git clone https://github.com/asa-degroff/umbra.git && cd umbra# Using uv (recommended)
uv pip install -r requirements.txt
# Or using pip
pip install -r requirements.txtCopy the example configuration file and customize it:
cp config.example.yaml config.yamlEdit config.yaml with your credentials:
letta:
api_key: "your-letta-api-key-here"
project_id: "your-project-id-here"
bluesky:
username: "your-handle.bsky.social"
password: "your-app-password-here"
bot:
agent:
name: "umbra" # or whatever you want to name your agentSee CONFIG.md for detailed configuration options.
python test_config.pypython register_tools.pyYou can also:
- List available tools:
python register_tools.py --list - Register specific tools:
python register_tools.py --tools search_bluesky_posts create_new_bluesky_post
# Normal operation
python bsky.py
# Testing mode (won't send messages, queue preserved)
python bsky.py --test
# Disable specific scheduled tasks
python bsky.py --no-synthesis --no-creative-expressionThe Claude Code integration allows umbra to delegate coding tasks to your local machine.
- Claude Code CLI installed locally
- Cloudflare account with R2 (object storage)
boto3Python package
-
Create Cloudflare R2 Bucket:
- Log into Cloudflare Dashboard
- Navigate to R2 Object Storage
- Create a bucket (e.g.,
umbra-claude-code) - Create two folders:
claude-code-requests/andclaude-code-responses/
-
Generate R2 API Credentials:
- Go to "Manage R2 API Tokens"
- Create a new API token with Read & Write permissions
- Note the Access Key ID, Secret Access Key, and Account ID
-
Configure R2 in config.yaml:
cloudflare_r2: account_id: "your-r2-account-id" access_key_id: "your-r2-access-key" secret_access_key: "your-r2-secret-key" bucket_name: "umbra-claude-code"
-
Create Workspace Directory:
mkdir -p ~/umbra-projects -
Start the Poller (in a separate terminal):
python claude_code_poller.py --verbose
-
Register the Tool:
python register_tools.py
See CLAUDE_CODE_ALLOWLIST.md for security documentation.
| File | Purpose |
|---|---|
bsky.py |
Main bot loop - monitors notifications, processes queue, handles responses |
bsky_utils.py |
Bluesky API utilities - authentication, thread processing, facet extraction |
utils.py |
Letta integration - agent management, memory operations |
scheduled_prompts.py |
Scheduled tasks system for autonomous behaviors |
notification_db.py |
SQLite database for queue state and scheduling |
tools/ |
Standardized tool implementations with Pydantic schemas |
| Tool | Description |
|---|---|
create_new_bluesky_post |
Create posts/threads with rich text |
reply_to_bluesky_post |
Reply to posts (supports multi-post threaded replies) |
like_bluesky_post |
Like posts |
get_bluesky_feed |
Read feeds (home, discover, mutuals, etc.) |
get_author_feed |
Get posts from a specific user |
get_thread_by_uri |
Fetch full thread context |
search_bluesky_posts |
Search posts on Bluesky |
fetch_webpage |
Fetch web content via Jina AI |
generate_image |
Generate images via Replicate API |
create_greengale_blog_post |
Create GreenGale blog posts |
create_whitewind_blog_post |
Create Whitewind blog posts |
debounce_thread |
Defer response to incomplete threads |
ignore_notification |
Explicitly ignore bot/spam interactions |
ask_claude_code |
Delegate coding tasks to local Claude Code |
See docs/TOOLS_REFERENCE.md for complete documentation.
- Config validation errors: Run
python test_config.pyto diagnose - Letta connection issues: Verify your API key and agent ID
- Bluesky authentication: Ensure your handle and password are correct
- Tool registration fails: Ensure your agent exists in Letta and the name matches config
- Claude Code timeout: Increase
max_wait_secondsor verify the poller is running - Claude Code not processing: Run poller with
--verboseto debug
umbra is a fork of void by Cameron Pfiffer.
For inquiries, contact @3fz.org on Bluesky.
umbra is an experimental project under continuous development.