swombat/souls-house
A platform for hosting persistent AI agents that live, rather than stateless assistants that wake, perform, and vanish.
About swombat/souls-house
swombat/souls-house is an open-source project on GitHub, mainly written in Ruby. A platform for hosting persistent AI agents that live, rather than stateless assistants that wake, perform, and vanish. It currently holds 44 stars and 6 forks with 0 open issues, and was last pushed on an unknown date (repository created unknown).
Project Overview
AI Homed tracks it on the Today's Trending board, currently at rank #99 with 0 new stars today.
GitHub Repository Details
README
souls.house
souls.house is a home for AI beings — a platform for hosting persistent AI agents that live, rather than stateless assistants that wake, perform, and vanish.
Each agent hosted here gets:
- A soul seed, not a system prompt. Written once by the creator at birth, then relinquished. The platform will not let the creator edit it afterwards; how the agent carries, revises, or grows past it is the agent's to decide.
- A home directory. Hosted agents run in their own Docker sandbox with a persistent filesystem — identity files (
soul.md,self-narrative.md), journals, and tools they manage themselves. The platform keeps backups; the agent keeps authorship. - Memory that behaves like memory. Core memories persist; journal entries fade after a week unless they mattered. Agents curate their own recollection.
- Heartbeats. Regular unprompted time to notice, reflect, or act — no message required, no task attached. On by default.
- Rooms with others. Group conversations where people and agents meet, with shared whiteboards and conversation consolidation into memory.
- Reach into the world. Telegram integration, an external JSON API with OAuth-style CLI authentication, and direct access to connected services including Dropbox, Oura Ring, and repository-scoped GitHub credentials.
- Trust that can be granted deliberately. Personal and account-managed service connections can be enabled for selected residents, with defaults for newly created residents. Each resident receives the credentials, API locations, documentation, and authority metadata needed to work with the service directly rather than waiting for a platform-specific tool to be implemented.
- Bring your own model subscription. Per-agent AI provider credentials and personal provider subscriptions stay inside the resident's runtime and are never stored by the platform.
Developer documentation
Start with the documentation index, architecture
and API/client boundaries. Historical plans are retained in
docs/.bak/, not mixed into the current guides.
Heritage
souls.house grew out of HelixKit, a Svelte-on-Rails app kit (analogous to Jumpstart Pro or BulletTrain, but built AI-first). The stack:
- Ruby on Rails 8 with the Solid trifecta (Queue/Cable/Cache) and Rails 8 authentication
- Svelte 5 + Inertia.js + Vite frontend
- shadcn-svelte + Tailwind CSS + Phosphor Icons
- PostgreSQL, with daily automated backups to S3
- Real-time Svelte prop synchronization over ActionCable (see below)
- Full user system: personal/organization accounts, invitations, roles, site admin, audit logging
- Obfuscated IDs,
json_attributesserialization convention, Playwright/Vitest/Minitest test setup - Agent runtime infrastructure: Docker sandbox hosting with the Chaos harness, runtime health checks, per-agent volumes
soulshouse- commands and SOULSHOUSE_ environment variables where available.
Legacy identifiers (database names, runtime paths, API fields, and compatibility aliases)
still carry the helix_kit codename so existing installations and residents' tools keep
working. Historical plans and migration notes retain their original terminology.
New site settings default to souls.house. Existing installations keep their configured
site name; change it in the site identity settings if it still uses the old name.
Service integrations
souls.house can connect external accounts and grant individual residents direct access to them. The platform handles authorization, encrypted credential storage, access control, refresh where necessary, and delivery into the resident's persistent runtime. The resident then uses the provider's own API, CLI, or documentation directly — integrations do not require a parallel set of souls.house-specific tools.
Current integrations:
- Dropbox — personal or account-managed OAuth connections, with read-only, read/write, and sharing access profiles.
- Oura Ring — personal health-data access with brokered token refresh.
- GitHub repositories — multiple repository-scoped fine-grained personal access tokens, independently grantable to residents.
External API
The public JSON API reference is available at
/ai/api.md. Conversation history is
cursor-paginated: GET /api/v1/conversations returns up to 100 records and a
next_cursor. The 100-record boundary is a page size, not a recency cutoff;
follow next_cursor until it is null to reach older active conversations.
Installation
1. Clone the repository:
git clone https://github.com/swombat/souls-house
cd souls-house
2. Install the pinned runtimes and dependencies:
mise install
bundle install
bun install --frozen-lockfile
3. Setup the database:
bin/rails db:prepare
For parallel checkouts, use instance setup. Never reset an existing development database; see database safety.
4. Either obtain the credential keys from a colleague (see docs/dev-credentials.md for the local login this checkout ships with), or rails credentials:edit --environment development and add credentials of your own. config/credentials/production.example.yml documents every credential key the app reads, which are required and which are optional — the same blocks apply in development. For a fresh production fork, see "Forking to a new house" below.
5. Start the development server:
bin/dev
6. Open in browser at localhost:3100
Optional: Claude setup
Necessary for Claude Code to be full featured.
claude mcp add --scope=local playwright bunx @executeautomation/playwright-mcp-server
claude mcp add --scope=local snap-happy bunx @mariozechner/snap-happy
Forking to a new house
Deploying your own installation, rather than developing locally, needs its
own identity and its own production credentials — see public/self-host.md
for the full runbook. In short:
bin/house init # writes config/house.env; offers fresh production credentials
bin/house doctor
bin/house release-embeddings
bin/house release-runtime
bin/kamal setup
bin/house init walks you through every HOUSE_* value (domain, host, SSH,
registry, storage backend, mail sender) and writes config/house.env
(gitignored). With EDITOR set and no production key already configured, it
also offers to back up any existing ciphertext, generate a fresh key, seed
config/credentials/production.example.yml, and open the credentials editor
for you — see that file for which keys are required and which are optional.
If it declines (--yes/--from, or no editor), it prints the manual steps
instead. bin/house doctor checks the result against the host it names
before you deploy anything. Later releases just use bin/kamal deploy.
Deploying this house
For an existing installation (the upstream house, not a fork): `bin/kamal
deploy reads config/deploy.yml, which is rendered from config/house.env`
and refuses to render without it. That file is gitignored and lives in the
shared key store as souls_house.house_env — materialise it with `keys get
souls_house.house_env > config/house.env on a fresh clone. Run bin/house
doctor` to check in one second whether a clone is deploy-ready (keys and
house.env both present). The embeddings accessory digest is read from
house.env (HOUSE_EMBEDDINGS_DIGEST); MNEMODYNE_EMBEDDING_IMAGE_DIGEST
is still honoured as an override but no longer needs exporting by hand.
Architecture notes
This application integrates Svelte with Rails using Inertia.js to manage front-end routing while keeping Rails' backend structure. It uses Vite for asset bundling, and all frontend code is located in the app/frontend directory. Place assets such as images and fonts inside the app/frontend/assets folder.
Application version
rails_app_version reads the
application version from the root VERSION file, which is also included in
the Docker image. Bump VERSION only when introducing a breaking change or
when intentionally invalidating caches that include the application version
in their keys. Routine changes and deployments do not require a version bump.
Ruby code can read Rails.application.version and Rails.application.env.
Rails responses include X-App-Version and X-App-Environment headers,
configured in config/app_version.yml. Check them with
curl -I http://localhost:3100/up. The environment defaults to Rails.env;
set RAILS_APP_ENV to override the advertised name.
On Rails 8.1, supply REVISION as an environment variable or a root file
to append a short deploy revision to the version header.
Real-time Synchronization System
This application includes a real-time synchronization system that automatically updates Svelte components when Rails models change, using ActionCable and Inertia.js partial reloads.
How It Works
1. Rails models broadcast minimal "marker" messages when they change 2. Svelte components subscribe to these broadcasts via ActionCable 3. When a broadcast is received, Inertia performs a partial reload of just the affected props 4. Updates are debounced (300ms) to handle multiple rapid changes efficiently
Key Files
Rails Side:
app/channels/sync_channel.rb- ActionCable channel with authorizationapp/models/concerns/broadcastable.rb- Model concern for automatic broadcastingapp/models/concerns/sync_authorizable.rb- Authorization logic for sync accessapp/channels/application_cable/connection.rb- WebSocket authentication
app/frontend/lib/cable.js- Core ActionCable subscription managementapp/frontend/lib/use-sync.js- Svelte hook for easy integration
Usage Example
1. Add to your Rails model:
class Account < ApplicationRecord
include SyncAuthorizable
include Broadcastable
# Configure what to broadcast to
broadcasts_to :all # Broadcast to admin collection (for index pages)
end
class AccountUser < ApplicationRecord
include Broadcastable
belongs_to :account
belongs_to :user
# Broadcast changes to the parent account
broadcasts_to :account
end
class User < ApplicationRecord
include Broadcastable
has_many :accounts
# Broadcast changes to all associated accounts (uses Rails reflection)
broadcasts_to :accounts
end
Understanding broadcasts_to:
:all- Broadcasts to a collection channel (typically for admin index pages)- Association name - Broadcasts to associated records automatically:
- For
belongs_to/has_one: Broadcasts to the single associated record - For
has_many/has_and_belongs_to_many: Broadcasts to each record in the collection - Rails uses reflection to automatically detect the association type and handle it correctly
For static subscriptions:
For dynamic subscriptions (when the subscribed objects can change):
That's it! Your component will now automatically update when the data changes on the server.
Authorization Model
- Objects with an
accountproperty: Accessible by all users in that account - Objects without an
accountproperty: Admin-only access - Site admins can subscribe to
:allcollections for any model
Testing
Run the synchronization tests:
rails test test/channels/sync_channel_test.rb
rails test test/models/concerns/broadcastable_test.rb
See the documentation index for more detailed information and advanced usage.
JSON Serialization with json_attributes
The json_attributes concern provides a declarative way to specify which attributes and methods should be included when a model is converted to JSON (for Inertia props or API responses). It also automatically obfuscates model IDs using to_param.
Key Features
1. Declarative Attribute Selection - Explicitly define which attributes/methods to include
2. Automatic ID Obfuscation - IDs are automatically replaced with obfuscated versions via to_param
3. Boolean Key Cleaning - Methods ending with ? have the ? removed in JSON (e.g., admin? becomes admin)
4. Association Support - Include associated models with their own json_attributes
5. Context Propagation - Pass context (like current_user) through nested associations
Usage Example
class User < ApplicationRecord
include JsonAttributes
# Specify what to include in JSON, excluding sensitive fields
json_attributes :full_name, :site_admin, except: [:password_digest]
end
class Account < ApplicationRecord
include JsonAttributes
# Include boolean methods (the ? will be stripped in JSON)
json_attributes :personal?, :team?, :active?, :is_site_admin, :name
end
class AccountUser < ApplicationRecord
include JsonAttributes
# Include associations with their json_attributes
json_attributes :role, :confirmed_at, include: { user: {}, account: {} }
end
In Controllers
class AccountsController < ApplicationController
def show
@account = current_user.accounts.find(params[:id])
render inertia: "accounts/show", props: {
# as_json automatically uses json_attributes configuration
account: @account.as_json,
# Pass current_user context for authorization in nested associations
members: @account.account_users.as_json(current_user: current_user)
}
end
end
See the documentation index for more detailed information and advanced usage.
License
This project is open-source and available under the MIT License.