What Happy Enterprise is
The engine behind all of an organization's data. Its people, apps, and agents work on the same records under the same checks, and it changes safely as the work changes.
Each organization gets its own members, teams, permissions, and ontology: typed object types and links that describe its work (customers, projects, incidents, machines, and how they relate), and the business actions that change them. People, assistants, and agent accounts all work on the same objects under the same rules.
When the work changes, the model changes with it, while the system runs. A new kind of record or a new field is usable at once. A new rule applies to every write at once and to the stored objects in the background, with each object marked valid, invalid, or pending, and invalid ones kept visible rather than dropped. A removed field is gone at once and its values never come back. Every object type and action keeps its versions, new actions and validators are defined at runtime, and permissions and the isolation between organizations apply throughout. See Versions and schema changes.
Happy Enterprise comes with a web app for the people in an organization and a console for the operator. It is one Rust binary on top of one Postgres database, serving two HTTP APIs on two separate listeners:
- The organization API (default
0.0.0.0:8080, the public one) is what your organizations’ people, agents, and apps use, the web app included: login, members and teams, the ontology, actions, the live event stream, OAuth, and an MCP server. - The management API (default
127.0.0.1:9090) is for you, the operator: it creates organizations and registers the signing keys of their identity providers.
The Docker image runs the server, the web app and Postgres in one container.
The design is inspired by Palantir’s: access to every type is a matter of permissions granted to teams and audited, and the web app, a person using an assistant, and a background agent all refer to the same incident and meet the same validation and permission checks. You can build your own apps on the same API. How it fits shows where your agents, models, data, and apps come in.
What an organization gets
Everything below is per organization, and nothing in one organization can see or affect another.
| People and agents | Human users sign in to the server with one emailed code and pick an organization, or sign in at an organization’s own address with a code or a password. Assistants act for a signed-in person over MCP; agent accounts act as themselves with API tokens. See How it fits and Users, teams, permissions. |
| Teams and permissions | The system teams owners and everyone, custom teams that are objects of the ontology, subteams that pass their members up, memberships that end on time, a history of every membership change, and eight permissions granted to teams. |
| Login and security posture | Server-wide sign-in, optional self-service sign-up, email codes, passwords, invites, DNS-verified allowed domains, required two-factor authentication with TOTP or WebAuthn. See Authentication. |
| An ontology | Object types with typed properties and format rules, versioned schemas, custom validators in sandboxed Python, link types with cardinality, queries, and access per type, down to the objects shared with each member or their teams and to single properties. See The ontology. |
| Business actions | The organization’s own operations, such as “open a work order”: typed parameters, criteria, edits applied all or nothing, safe retries, webhooks and emails (to members or customers) after commit, and an audit log. See Business actions. |
| Timeseries | Series of timestamped points, such as sensor readings, attached to objects and read under their access: idempotent batches, raw, bucketed and downsampled reads, the newest value, retention, and live updates. See Timeseries. |
| Chat | Public and private channels, direct messages, and channels about one object that follow who sees it, for people and agents: threads, mentions, attachments, reactions, pins, read state, and typing. See Chat. |
| Filesystems | Trees of folders and files: versioned uploads up to 25 MiB, paths, name search, a trash with restore, folders restricted to teams that hide everything under them, live updates, and MCP tools. See Filesystems. |
| Search | One full-text search across objects’ text, chat messages, and file names and text, ranked, with highlighted snippets, finding only what each person could open. See Search. |
| Live updates | Every change to the ontology as a resumable stream of server-sent events. See Live events. |
| An MCP server | At /orgs/{org}/mcp, behind the organization’s own OAuth 2.1 authorization server, with scoped MCP tokens for agents and scripts. See MCP and OAuth. |
| Connectors | Outside MCP servers the organization connects, their tools reviewed before anyone sees them, granted to teams with limits on their arguments, called through the organization’s MCP endpoint or from actions, and logged. See Connectors. |
| A web app | Objects in tables and calendars, the ontology and its code editor, action forms, the audit log, the live feed, people, teams, security, and an operator console. See Web app. |
| Files | Avatars, an organization photo, and attachments up to 25 MiB, readable by whoever may see an object that refers to them. In a local directory or an S3 bucket. See Files and email. |
How it is kept apart
Isolation between organizations is enforced three times over:
- Scoped transactions. Request handlers never see a connection pool. The only database handle they get is a transaction opened for a verified credential, scoped to that credential’s organization.
- Postgres row level security. Every table has forced RLS. Every row of organization data records its organization, and one policy, for reads and writes, matches only rows of the transaction’s organization. The runtime roles cannot bypass it.
- Tests. Integration tests try to read and write across organizations in every table, and check that every table carries the policy.
Organizations and isolation explains each layer, and what it does not cover.
The stack
- Rust (axum, sqlx, tokio): one binary,
happy-enterprise. - Postgres 16 or newer. All state lives there; ids are cuid2, generated by the application.
- Pydantic Monty, a Python interpreter written in Rust, for custom ontology validators.
- rmcp for the MCP server.
Current limits
What Happy Enterprise does not do yet. Each item comes off this list when it ships.
- Access does not follow links. A team sees all objects of a type, or only the ones that name the member or a team of theirs (an assignee, an owner, a list of viewers or teams), and single properties can be limited to some teams. But a manager does not see their reports’ expenses, and a document does not inherit its folder’s sharing. Writes can be narrowed further through business actions.
- Actions see and change only what they are given. Criteria see their parameters’ objects, the links between them, and the kind and teams of the caller and the users those objects and parameters name. Edits change those objects, the objects the action creates, and memberships of the teams passed in. So an action cannot update every document in a folder, and its criteria cannot ask whether a car has any reservation.
- Schedules have fixed parameters, and nothing reacts to events. A schedule applies one action with the same parameters each time, so it cannot release whichever reservations have run out. No action runs because another was applied or an event arrived, and there is no signed inbound webhook endpoint: integrations report with an API token.
- Times are UTC. Schedules and anything an action computes from the time have no time zone per organization.
- Emails go to one person each. An action emails a member or an outside address, not a team.
- Connectors act as one identity at the remote. Every call to an outside MCP server goes out with the organization’s credential there, whoever made it; the call log records who did. Their resources and prompts are not served, and calls send no live events.
- Every reader is a member. There are no share links for people outside the organization, in the API or in the web app.
- Search has no stemming, and skips attachments. Search matches words and their prefixes, not their other forms, and does not look inside struct properties, message fields, attached files, or earlier versions of files. Very common words are slower.
- No transactions outside actions. Plain object and link writes are one operation each. A change that takes several steps is atomic only when it is defined as an action.
- No property indexes. Filters and sorts on properties scan the type’s
objects, so those that must look at every object, such as
starts_withororder_byon a property, take 1.3 to 2.3 seconds at a million objects of a type. Lookups by id, link traversals, andlinkedfilters use indexes. See Performance. - MCP posts no chat attachments. Assistants post text and fields only.
- Single points cannot be deleted. Points of a timeseries go when retention passes them or their series goes, and ingest limits count batches, not points.
- Filesystem uploads are single requests. A filesystem takes uploads of up to 25 MiB in one request, and keeps every version until its file is purged from the trash. Its own name search is a substring match that reads the whole tree.
- Files have no quota or cleanup. Uploads are limited to 25 MiB each, but not in total, and attachments that no object refers to are kept. MCP clients cannot upload attachments, though they can write files in a filesystem.
Where to go next
- How it fits: what runs your agents, how they connect, and where your data and UI come from.
- Quickstart: run it locally, create an organization, log in, and define an object type.
- Use cases: complete examples, machine maintenance, document management, car sales, an agentic dev team, and a smart home, each run end to end.
- API reference: every endpoint, with examples.
- Docker and Deploying: running it, roles, configuration.