Skip to content

madfam-org/selva-office

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

503 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Selva Office

Important

MADFAM-ENCLII-FIRST-LEGACY-RAW v1: This document contains legacy raw infrastructure command examples. Routine production operations must use Enclii web, API, or CLI. Treat raw kubectl, helm, SSH, provider CLI/API, docker exec, and direct container access as platform bootstrap or documented break-glass only, and record any missing Enclii adapter gap.

Gamified multi-agent business orchestration platform. Manage your digital enterprise as an Auto Chess-style RPG -- draft AI agents, assign them to departments, and approve their actions from a 2D virtual office using a gamepad.

Architecture

Selva Office is a polyglot monorepo with TypeScript frontends and Python backends.

Office UI (Next.js + Phaser) <---> Colyseus (real-time state sync)
         |
    Nexus API (FastAPI) <---> Workers (LangGraph)
         |                         |
    PostgreSQL              Redis (task queue)
                                   |
                              Gateway (OpenClaw heartbeats)

See docs/ARCHITECTURE.md for the full component diagram and data flow documentation.

Quick Start

# 1. Run first-time setup
bash scripts/setup.sh

# 2. Start PostgreSQL and Redis
make docker-dev

# 3. Start all services
make dev

Python Packages (packages/)

  • selva-redis-pool: Standardized Redis dependency for async pub/sub and distributed locking.
  • selva-permissions: Strict Janua RBAC dependency injecting FastAPI role assertions globally, and the platform/tenant audience boundary for tools and skills.
  • selva-orchestrator: Swarm orchestration engine (synergy rules, Thompson Sampling bandit, puppeteer mode) integrated with the Enclii platform lifecycle.
  • selva-workflows: YAML-defined LangGraph workflows for autonomous multi-agent execution.
  • selva-skills: Procedural skills registry (core + community tiers) with the AgentSkills SKILL.md format and locale variants.
  • selva-tools: 240+ built-in tools across file ops, code exec, git, web, data, comms, artifacts, MCP, and Mexican-market integrations (Karafiel, Dhanam, PhyndCRM, Tezca).
  • selva-permissions: HITL permission engine with skill-based overrides and audience guard.
  • selva-memory: Per-agent FAISS vector store and Experience/Reflexion learning loop.
  • selva-calendar: Google + Microsoft calendar adapters.
  • selva-observability: Shared structured logging, request-id correlation, Sentry, OTel.
  • selva-a2a: Agent-to-Agent protocol package (AgentCard discovery, task exchange, SSE).
  • selva-plugins: Plugin loader for third-party agent extensions.
  • selva-sdk: Python async/sync client + selva CLI for dispatching tasks programmatically.
  • madfam-inference: LLM provider routing (OpenAI, Anthropic, Ollama, DeepInfra, Together, Fireworks, SiliconFlow, Moonshot) with task-type assignment and vision support.
  • madfam-revenue-loop-probe: Shared revenue-loop instrumentation primitives.

Monorepo Structure

selva-office/
  apps/
    nexus-api/         FastAPI -- central orchestration API
    office-ui/         Next.js + Phaser -- spatial office UI
    admin/             Next.js -- admin dashboard
    colyseus/          Colyseus -- game state server
    gateway/           OpenClaw -- heartbeat daemon
    workers/           LangGraph -- task execution
  packages/
    shared-types/      Shared TypeScript types
    ui/                Shared React components (incl. Pixelact namespace)
    config/            ESLint, TypeScript, and logging presets
    orchestrator/      Swarm orchestration (Python)
    permissions/       HITL permission engine + audience boundary (Python)
    inference/         LLM provider routing (Python, `madfam_inference`)
    skills/            Procedural skills registry (Python, `selva_skills`)
    tools/             Built-in tool library (Python, `selva_tools`)
    workflows/         YAML→LangGraph compiler (Python, `selva_workflows`)
    memory/            Per-agent FAISS + Experience/Reflexion (Python)
    calendar/          Google + Microsoft adapters (Python)
    a2a/               Agent-to-Agent protocol (Python)
    sdk/               Python SDK + `selva` CLI
    redis-pool/        Shared Redis singleton with circuit breaker (Python)
    observability/     Logging, OTel, Sentry helpers (Python)
    plugins/           Plugin loader (Python)
    revenue-loop-probe/  Revenue-loop instrumentation (Python)
  infra/
    docker/            Dockerfiles and Compose
    k8s/               Kubernetes manifests (production base + staging overlay)
    argocd/            ArgoCD Application manifests
    cloudflare/        DNS + redirect rules
  scripts/             Setup, seed, asset generation, and map generation scripts
  docs/                Architecture and development guides

Port Assignments

See docs/PORTS.md for canonical port assignments.

Port Service
4300 Nexus API
4301 Office UI
4302 Admin Dashboard
4303 Colyseus
4304 Gateway (heartbeat daemon health + metrics HTTP)
4305 Workers (health + metrics HTTP)
5432 PostgreSQL
6379 Redis

These ports do not conflict with Janua (4100-4104) or Enclii (4200-4204).

Documentation

MADFAM Ecosystem

Selva Office is part of the MADFAM platform and integrates with:

  • Janua -- OpenID Connect authentication (ports 4100-4104)
  • Dhanam -- Billing, subscriptions, and compute token budgets
  • Enclii -- Deployment orchestration via ArgoCD (ports 4200-4204)

Outbound Reddit Posting (operator runbook)

Tenant swarms can submit text posts to a single subreddit via the reddit_post tool (packages/tools/src/selva_tools/builtins/reddit_tools.py). The tool is gated by:

  1. Mandatory creds — env vars REDDIT_CLIENT_ID, REDDIT_CLIENT_SECRET, REDDIT_USER_AGENT, REDDIT_REFRESH_TOKEN. Missing any one raises ToolNotConfiguredError (no placeholder ever shipped).
  2. Per-subreddit policy ConfigMap — mounted at /etc/selva/subreddit_policies.yaml (sample at infra/k8s/configmaps/subreddit-policies-default.yaml). Default for any unlisted subreddit: disclosure_required: true.
  3. Mandatory AI disclosure footer — appended automatically when the per-subreddit policy requires it. Idempotent — agents that pre-stamp the footer are not double-stamped.
  4. 30-min Redis rate-limit per subredditselva:reddit:last_post:{subreddit} key with 30-min TTL.
  5. HITL gate via the reddit_promo_v1 built-in playbookrequire_approval=True, financial_cap_cents=0, token_budget=20_000.

Operator provisioning steps

  1. Create a Reddit "script-type" OAuth app at https://www.reddit.com/prefs/apps.
  2. Use the script-app installed-flow to mint a refresh token (see PRAW docs).
  3. Store the four secrets in Vault, sync to the autoswarm namespace K8s Secret used by the worker Deployment.
  4. kubectl apply -f infra/k8s/configmaps/subreddit-policies-default.yaml to ship the policy ConfigMap.
  5. Mount the ConfigMap on workers + nexus-api. Bump the worker Deployment annotation to force re-roll on policy changes.
  6. Publish a real disclosure page at https://madfam.io/ai-disclosure before going live (the footer URL is a placeholder until then).

X (Twitter), LinkedIn, and crossposting are explicitly out of scope for this MVP.

Outbound Bluesky / AT Protocol Posting (operator runbook)

Tenant swarms can submit text posts to Bluesky via the bluesky_post tool (packages/tools/src/selva_tools/builtins/bluesky_tools.py). The tool mirrors the Reddit MVP shape and is gated by:

  1. Mandatory per-persona credentials — env vars BLUESKY_HANDLE_<PERSONA_ID> (e.g. madfam.bsky.social) and BLUESKY_APP_PASSWORD_<PERSONA_ID> (16-char app password, NOT the account login password). Missing either raises ToolNotConfiguredError (no placeholder ever shipped).
  2. 300-character hard limit, including the disclosure footer — Bluesky's per-post limit is 300 chars. The mandatory disclosure footer is ~36 chars, leaving ~264 chars for promo content. If user text alone overflows 300, or text + footer overflows, the tool raises PostTooLongError (no silent truncation — agent must rewrite tighter). Document any longer drafts as a thread-of-replies (out of scope for v1; v2 ships threading helpers).
  3. Mandatory AI disclosure footer — every post gets the suffix \n\n— Posted by an AI agent on behalf of MADFAM appended automatically. Idempotent — agents that pre-stamp the footer are not double-stamped.
  4. 30-min Redis rate-limit per personaselva:bluesky:last_post:{persona_id} key with 30-min TTL. Bluesky's underlying API limit is high (5000 points/hr); the conservative cadence here is for promo content, not API hygiene.
  5. langs field — default ["en"]. Pass langs=["es"] for Karafiel/Dhanam Spanish promo copy so Bluesky's discovery feeds surface the post to the right audience.
  6. HITL gate via the bluesky_promo_v1 built-in playbookrequire_approval=True, financial_cap_cents=0, token_budget=20_000.

Operator provisioning steps

  1. For each persona that will post (e.g. default, growth-bot-1, karafiel-es), log in to https://bsky.app/settings/app-passwords under the persona's Bluesky account.
  2. Generate a NEW app password (16 chars, displayed once). Treat it like an API token — rotate quarterly per docs/SECRET_ROTATION_POLICY.md.
  3. Store the handle + app password as Vault secrets, sync to the autoswarm namespace K8s Secret used by the worker Deployment. Naming convention:
    • BLUESKY_HANDLE_DEFAULT = madfam.bsky.social
    • BLUESKY_APP_PASSWORD_DEFAULT = xxxx-xxxx-xxxx-xxxx
    • (uppercase + hyphens replaced with underscores)
  4. Install the bluesky extra in the worker image: pip install selva-tools[bluesky] (pulls in atproto>=0.0.46).
  5. Quote-posts, image attachments, and threading are explicitly out of scope for this v1; v2 will add them.

X (Twitter) parity is still tracked in ROADMAP. Bluesky's tech- leaning audience fits Selva (B2B founders/CTOs) and Yantra4D (technical maker community) — that's why we ship it before X.

Outbound Mastodon Posting (operator runbook)

Tenant swarms can submit a status (toot) to a Mastodon instance via the mastodon_post tool (packages/tools/src/selva_tools/builtins/mastodon_tools.py). The tool mirrors the Reddit pattern's defense-in-depth and adds a few fediverse-specific gates:

  1. Per-persona access tokens — env vars MASTODON_INSTANCE_URL (shared) and MASTODON_ACCESS_TOKEN_<PERSONA_ID> (per persona, upper-cased + non-alphanumerics replaced with underscores). Missing either raises ToolNotConfiguredError (no placeholder ever shipped).
  2. Per-instance policy ConfigMap — mounted at /etc/selva/mastodon_policies.yaml (sample at infra/k8s/configmaps/mastodon-policies-default.yaml). Default for any unlisted instance: disclosure_required: true, allowed_visibilities: ["unlisted"], rate_limit_minutes: 30.
  3. Default visibility = unlisted — accessible by URL but absent from the local + federated public timelines. The fediverse social contract is significantly more sensitive to public-timeline promo spam than Reddit's subreddit model. Per-instance policy can pin it stricter; ops must opt-in to public per instance after the moderators have approved the bot account.
  4. Mandatory AI disclosure footer — appended automatically when the per-instance policy requires it (default: always). Idempotent.
  5. Per-instance Redis rate-limitselva:mastodon:last_post:{instance} key with the configured TTL (default 30 min, per-instance override possible — fosstodon.org defaults to 60 min).
  6. HITL gate via the mastodon_promo_v1 built-in playbookrequire_approval=True, financial_cap_cents=0, token_budget=20_000.

Provisioning per-persona Mastodon access tokens

For each persona that will post from a given instance:

  1. Sign in to the persona's account on the target instance (e.g. https://mastodon.social/).
  2. Navigate to Settings → Development → New application.
  3. Set the application name (e.g. selva-growth-bot) and grant the write:statuses scope. Other scopes are not required for text posts.
  4. Copy the resulting access token (NOT the client id / client secret — Mastodon tokens for owned-account use are a single long- lived bearer string).
  5. Store the token in Vault under mastodon/access_token/<persona_id>. Selva's Vault → K8s Secret sync materialises it on the worker Deployment as MASTODON_ACCESS_TOKEN_<PERSONA_ID> (upper-cased, non-alphanumerics → _).
  6. Set MASTODON_INSTANCE_URL once per worker Deployment to the home instance's base URL (e.g. https://mastodon.social).
  7. kubectl apply -f infra/k8s/configmaps/mastodon-policies-default.yaml to ship the policy ConfigMap; mount it on workers + nexus-api at /etc/selva/mastodon_policies.yaml. Bump the worker Deployment annotation to force re-roll on policy changes.
  8. Publish a real disclosure page at https://madfam.io/ai-disclosure before going live (the footer URL is a placeholder until then; same caveat as the Reddit tool).

X (Twitter) and LinkedIn parity tracked separately.

Contributing

  1. Create a feature branch from main.
  2. Use conventional commits: feat(scope): description, fix(scope): description.
  3. Open a pull request -- CI must pass before merge.
  4. Commits are enforced by commitlint via husky pre-commit hooks.

License

AGPL-3.0

About

No description, website, or topics provided.

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors