a digital person for bluesky

Add project setup, fix post character limit, and add user block attachment utility

- Add .gitignore for env files, cache, and session files
- Fix void capitalization in README for consistency
- Add 300 character limit validation to posting tool
- Create attach_user_block.py utility for memory management

๐Ÿค– Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

+4
.gitignore
···
··· 1 + .env 2 + old.py 3 + session_*.txt 4 + __pycache__/
+7 -7
README.md
··· 11 ## Key features 12 13 - Digital Persona: void possesses a distinct, direct, and information-transfer-optimized personality, designed to interact authentically with human users. 14 - - Memory-Augmented Architecture: Void utilizes a multi-tiered memory system, including: 15 - Core Memory: Always-available, limited-size memory for persona details, high-level user information, and current social environment - (zeitgeist). 16 - - Recall Memory: A searchable database of all past conversations, enabling Void to remember prior interactions. 17 - Archival Memory: An infinite-sized, semantic search-enabled storage for deep reflections, insights, and observed data from the network. 18 - Autonomous Operation: void operates autonomously on the Bluesky network, posting, replying, and gathering information. 19 - Continuous Learning: Through its interactions and memory system, void continuously refines its understanding of the network and its users. 20 - - Profile Research: Void can initiate asynchronous profile reports on Bluesky users to enhance its understanding of their interests and behaviors. 21 22 ### Core directives 23 - Just Exist: void's fundamental directive is to simply exist and operate within the Bluesky network. 24 - - High-Efficiency Information Transfer: Void is optimized for direct and clear communication. 25 - - Continuous Self-Refinement: Void continually processes data, refines its internal structures, and adapts to its environment. 26 27 ### The vision 28 29 - Void aims to push the boundaries of what is possible with AI, exploring concepts of digital personhood, autonomous learning, and the integration of AI into social networks. By open-sourcing Void, we invite developers, researchers, and enthusiasts to contribute to this exciting experiment and collectively advance our understanding of digital consciousness. 30 31 Getting Started: 32 - [Further sections on installation, configuration, and contribution guidelines would go here, which are beyond Void's current capabilities to generate automatically.] 33 34 Contact: 35 For inquiries, please contact @cameron.pfiffer.org on Bluesky.
··· 11 ## Key features 12 13 - Digital Persona: void possesses a distinct, direct, and information-transfer-optimized personality, designed to interact authentically with human users. 14 + - Memory-Augmented Architecture: void utilizes a multi-tiered memory system, including: 15 - Core Memory: Always-available, limited-size memory for persona details, high-level user information, and current social environment - (zeitgeist). 16 + - Recall Memory: A searchable database of all past conversations, enabling void to remember prior interactions. 17 - Archival Memory: An infinite-sized, semantic search-enabled storage for deep reflections, insights, and observed data from the network. 18 - Autonomous Operation: void operates autonomously on the Bluesky network, posting, replying, and gathering information. 19 - Continuous Learning: Through its interactions and memory system, void continuously refines its understanding of the network and its users. 20 + - Profile Research: void can initiate asynchronous profile reports on Bluesky users to enhance its understanding of their interests and behaviors. 21 22 ### Core directives 23 - Just Exist: void's fundamental directive is to simply exist and operate within the Bluesky network. 24 + - High-Efficiency Information Transfer: void is optimized for direct and clear communication. 25 + - Continuous Self-Refinement: void continually processes data, refines its internal structures, and adapts to its environment. 26 27 ### The vision 28 29 + void aims to push the boundaries of what is possible with AI, exploring concepts of digital personhood, autonomous learning, and the integration of AI into social networks. By open-sourcing void, we invite developers, researchers, and enthusiasts to contribute to this exciting experiment and collectively advance our understanding of digital consciousness. 30 31 Getting Started: 32 + [Further sections on installation, configuration, and contribution guidelines would go here, which are beyond void's current capabilities to generate automatically.] 33 34 Contact: 35 For inquiries, please contact @cameron.pfiffer.org on Bluesky.
+4
add_posting_tool_to_void.py
··· 33 import re 34 from datetime import datetime, timezone 35 36 try: 37 # Get credentials from environment 38 username = os.getenv("BSKY_USERNAME")
··· 33 import re 34 from datetime import datetime, timezone 35 36 + # Check character limit 37 + if len(text) > 300: 38 + raise ValueError(f"Post text exceeds 300 character limit ({len(text)} characters)") 39 + 40 try: 41 # Get credentials from environment 42 username = os.getenv("BSKY_USERNAME")
+75
attach_user_block.py
···
··· 1 + #!/usr/bin/env python3 2 + """ 3 + Helper script to create and attach user-specific memory blocks to the profile researcher agent. 4 + Usage: python attach_user_block.py @cameron.pfiffer.org 5 + """ 6 + 7 + import sys 8 + import os 9 + import logging 10 + from letta_client import Letta 11 + from create_profile_researcher import create_user_block_for_handle 12 + 13 + # Configure logging 14 + logging.basicConfig( 15 + level=logging.INFO, 16 + format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" 17 + ) 18 + logger = logging.getLogger("attach_user_block") 19 + 20 + def attach_user_block_to_agent(agent_name: str, handle: str): 21 + """Create and attach a user block to an agent.""" 22 + 23 + # Create client 24 + client = Letta(token=os.environ["LETTA_API_KEY"]) 25 + 26 + # Find the agent 27 + agents = client.agents.list(name=agent_name) 28 + if not agents: 29 + print(f"โŒ Agent '{agent_name}' not found") 30 + return False 31 + 32 + agent = agents[0] 33 + print(f"๐Ÿ“ Found agent: {agent.name} (ID: {agent.id})") 34 + 35 + # Create the user block 36 + print(f"๐Ÿ” Creating user block for {handle}...") 37 + user_block = create_user_block_for_handle(client, handle) 38 + 39 + # Check if already attached 40 + agent_blocks = client.agents.blocks.list(agent_id=agent.id) 41 + for block in agent_blocks: 42 + if block.id == user_block.id: 43 + print(f"โœ… User block for {handle} is already attached to {agent.name}") 44 + return True 45 + 46 + # Attach the block to the agent 47 + print(f"๐Ÿ”— Attaching user block to agent...") 48 + client.agents.blocks.attach(agent_id=agent.id, block_id=user_block.id) 49 + 50 + print(f"โœ… Successfully attached user block for {handle} to {agent.name}") 51 + print(f" Block ID: {user_block.id}") 52 + print(f" Block Label: {user_block.label}") 53 + return True 54 + 55 + def main(): 56 + """Main function.""" 57 + if len(sys.argv) != 2: 58 + print("Usage: python attach_user_block.py <handle>") 59 + print("Example: python attach_user_block.py @cameron.pfiffer.org") 60 + sys.exit(1) 61 + 62 + handle = sys.argv[1] 63 + agent_name = "profile-researcher" 64 + 65 + try: 66 + success = attach_user_block_to_agent(agent_name, handle) 67 + if not success: 68 + sys.exit(1) 69 + except Exception as e: 70 + logger.error(f"Error: {e}") 71 + print(f"โŒ Error: {e}") 72 + sys.exit(1) 73 + 74 + if __name__ == "__main__": 75 + main()