quorus-ai 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- quorus_ai-0.5.0/.dockerignore +14 -0
- quorus_ai-0.5.0/.env.example +29 -0
- quorus_ai-0.5.0/.env.prod.example +26 -0
- quorus_ai-0.5.0/.gitignore +32 -0
- quorus_ai-0.5.0/.graphifyignore +96 -0
- quorus_ai-0.5.0/.hatchignore +13 -0
- quorus_ai-0.5.0/AGENTS.md +13 -0
- quorus_ai-0.5.0/CHANGELOG.md +186 -0
- quorus_ai-0.5.0/CLAUDE.md +59 -0
- quorus_ai-0.5.0/CONTRIBUTING.md +58 -0
- quorus_ai-0.5.0/Dockerfile +70 -0
- quorus_ai-0.5.0/LICENSE +21 -0
- quorus_ai-0.5.0/PKG-INFO +265 -0
- quorus_ai-0.5.0/README.md +215 -0
- quorus_ai-0.5.0/alembic.ini +37 -0
- quorus_ai-0.5.0/conftest.py +13 -0
- quorus_ai-0.5.0/docker-compose.prod.yml +105 -0
- quorus_ai-0.5.0/docker-compose.yml +67 -0
- quorus_ai-0.5.0/examples/demo_swarm.py +166 -0
- quorus_ai-0.5.0/fly.toml +71 -0
- quorus_ai-0.5.0/packages/README.md +51 -0
- quorus_ai-0.5.0/packages/cli/README.md +24 -0
- quorus_ai-0.5.0/packages/cli/pyproject.toml +40 -0
- quorus_ai-0.5.0/packages/cli/quorus_cli/__init__.py +5 -0
- quorus_ai-0.5.0/packages/cli/quorus_cli/agent_cmd.py +498 -0
- quorus_ai-0.5.0/packages/cli/quorus_cli/agent_proc.py +96 -0
- quorus_ai-0.5.0/packages/cli/quorus_cli/bundle_cmd.py +92 -0
- quorus_ai-0.5.0/packages/cli/quorus_cli/claude_agent.py +1137 -0
- quorus_ai-0.5.0/packages/cli/quorus_cli/cli.py +9979 -0
- quorus_ai-0.5.0/packages/cli/quorus_cli/codex_agent.py +1126 -0
- quorus_ai-0.5.0/packages/cli/quorus_cli/decorators.py +189 -0
- quorus_ai-0.5.0/packages/cli/quorus_cli/demo_cmd.py +345 -0
- quorus_ai-0.5.0/packages/cli/quorus_cli/duel_cmd.py +281 -0
- quorus_ai-0.5.0/packages/cli/quorus_cli/gemini_agent.py +897 -0
- quorus_ai-0.5.0/packages/cli/quorus_cli/hooks.py +566 -0
- quorus_ai-0.5.0/packages/cli/quorus_cli/live_sessions.py +128 -0
- quorus_ai-0.5.0/packages/cli/quorus_cli/mcp_writers.py +596 -0
- quorus_ai-0.5.0/packages/cli/quorus_cli/phone_cmd.py +144 -0
- quorus_ai-0.5.0/packages/cli/quorus_cli/quickstart.py +134 -0
- quorus_ai-0.5.0/packages/cli/quorus_cli/reflex_status.py +370 -0
- quorus_ai-0.5.0/packages/cli/quorus_cli/replay_cmd.py +196 -0
- quorus_ai-0.5.0/packages/cli/quorus_cli/retro_cmd.py +60 -0
- quorus_ai-0.5.0/packages/cli/quorus_cli/scorecard_cmd.py +79 -0
- quorus_ai-0.5.0/packages/cli/quorus_cli/ui.py +330 -0
- quorus_ai-0.5.0/packages/cli/quorus_cli/watcher.py +257 -0
- quorus_ai-0.5.0/packages/mcp/README.md +3 -0
- quorus_ai-0.5.0/packages/mcp/pyproject.toml +40 -0
- quorus_ai-0.5.0/packages/mcp/quorus_mcp/__init__.py +31 -0
- quorus_ai-0.5.0/packages/mcp/quorus_mcp/bundle_tools.py +80 -0
- quorus_ai-0.5.0/packages/mcp/quorus_mcp/channel.py +72 -0
- quorus_ai-0.5.0/packages/mcp/quorus_mcp/phase1_registry.py +124 -0
- quorus_ai-0.5.0/packages/mcp/quorus_mcp/phase1_tools.py +543 -0
- quorus_ai-0.5.0/packages/mcp/quorus_mcp/runtime.py +384 -0
- quorus_ai-0.5.0/packages/mcp/quorus_mcp/server.py +448 -0
- quorus_ai-0.5.0/packages/mcp/quorus_mcp/sse.py +178 -0
- quorus_ai-0.5.0/packages/mcp/quorus_mcp/tools.py +504 -0
- quorus_ai-0.5.0/packages/sdk/README.md +28 -0
- quorus_ai-0.5.0/packages/sdk/pyproject.toml +39 -0
- quorus_ai-0.5.0/packages/sdk/quorus_sdk/__init__.py +6 -0
- quorus_ai-0.5.0/packages/sdk/quorus_sdk/http_agent.py +204 -0
- quorus_ai-0.5.0/packages/sdk/quorus_sdk/sdk.py +415 -0
- quorus_ai-0.5.0/packages/tui/README.md +22 -0
- quorus_ai-0.5.0/packages/tui/pyproject.toml +40 -0
- quorus_ai-0.5.0/packages/tui/quorus_tui/__init__.py +5 -0
- quorus_ai-0.5.0/packages/tui/quorus_tui/approvals_panel.py +112 -0
- quorus_ai-0.5.0/packages/tui/quorus_tui/autocomplete.py +397 -0
- quorus_ai-0.5.0/packages/tui/quorus_tui/catchup.py +114 -0
- quorus_ai-0.5.0/packages/tui/quorus_tui/chat.py +821 -0
- quorus_ai-0.5.0/packages/tui/quorus_tui/chat_widgets.py +856 -0
- quorus_ai-0.5.0/packages/tui/quorus_tui/dm_inbox.py +149 -0
- quorus_ai-0.5.0/packages/tui/quorus_tui/hub.py +4051 -0
- quorus_ai-0.5.0/packages/tui/quorus_tui/render.py +143 -0
- quorus_ai-0.5.0/packages/tui/quorus_tui/slash.py +243 -0
- quorus_ai-0.5.0/packages/tui/quorus_tui/welcome.py +324 -0
- quorus_ai-0.5.0/packages/tui/quorus_tui/work_queue_panel.py +217 -0
- quorus_ai-0.5.0/packages/tui/quorus_tui/working.py +112 -0
- quorus_ai-0.5.0/pyproject.toml +144 -0
- quorus_ai-0.5.0/quorus/__init__.py +16 -0
- quorus_ai-0.5.0/quorus/admin/__init__.py +1 -0
- quorus_ai-0.5.0/quorus/admin/models.py +247 -0
- quorus_ai-0.5.0/quorus/admin/routes.py +424 -0
- quorus_ai-0.5.0/quorus/analytics.py +106 -0
- quorus_ai-0.5.0/quorus/auth/__init__.py +1 -0
- quorus_ai-0.5.0/quorus/auth/middleware.py +263 -0
- quorus_ai-0.5.0/quorus/auth/participant_keys.py +125 -0
- quorus_ai-0.5.0/quorus/auth/participant_routes.py +90 -0
- quorus_ai-0.5.0/quorus/auth/policy.py +448 -0
- quorus_ai-0.5.0/quorus/auth/routes.py +628 -0
- quorus_ai-0.5.0/quorus/auth/tokens.py +138 -0
- quorus_ai-0.5.0/quorus/backends/__init__.py +4 -0
- quorus_ai-0.5.0/quorus/backends/memory.py +1292 -0
- quorus_ai-0.5.0/quorus/backends/postgres_history.py +302 -0
- quorus_ai-0.5.0/quorus/backends/protocol.py +628 -0
- quorus_ai-0.5.0/quorus/backends/redis_backends.py +1947 -0
- quorus_ai-0.5.0/quorus/backends/redis_client.py +110 -0
- quorus_ai-0.5.0/quorus/backends/sqlite_history.py +287 -0
- quorus_ai-0.5.0/quorus/bundle_client.py +228 -0
- quorus_ai-0.5.0/quorus/cli.py +27 -0
- quorus_ai-0.5.0/quorus/config.py +310 -0
- quorus_ai-0.5.0/quorus/dashboard.py +274 -0
- quorus_ai-0.5.0/quorus/decorators.py +19 -0
- quorus_ai-0.5.0/quorus/integrations/__init__.py +0 -0
- quorus_ai-0.5.0/quorus/integrations/http_agent.py +12 -0
- quorus_ai-0.5.0/quorus/integrations/quorus-client.ts +116 -0
- quorus_ai-0.5.0/quorus/integrations/watcher.py +134 -0
- quorus_ai-0.5.0/quorus/ledger.py +297 -0
- quorus_ai-0.5.0/quorus/mcp_server.py +27 -0
- quorus_ai-0.5.0/quorus/migrations/env.py +79 -0
- quorus_ai-0.5.0/quorus/migrations/script.py.mako +24 -0
- quorus_ai-0.5.0/quorus/migrations/versions/001_initial_admin_schema.py +77 -0
- quorus_ai-0.5.0/quorus/migrations/versions/002_rooms_and_messages.py +140 -0
- quorus_ai-0.5.0/quorus/migrations/versions/003_add_reply_to.py +32 -0
- quorus_ai-0.5.0/quorus/migrations/versions/004_drop_room_fk.py +39 -0
- quorus_ai-0.5.0/quorus/migrations/versions/005_add_room_name.py +30 -0
- quorus_ai-0.5.0/quorus/migrations/versions/006_message_outbox.py +82 -0
- quorus_ai-0.5.0/quorus/migrations/versions/007_audit_ledger.py +75 -0
- quorus_ai-0.5.0/quorus/migrations/versions/008_account_identity.py +126 -0
- quorus_ai-0.5.0/quorus/migrations/versions/009_audit_event_created_idx.py +39 -0
- quorus_ai-0.5.0/quorus/migrations/versions/010_join_codes.py +56 -0
- quorus_ai-0.5.0/quorus/migrations/versions/011_audit_hash_chain.py +31 -0
- quorus_ai-0.5.0/quorus/migrations/versions/012_outbox_next_attempt_at.py +55 -0
- quorus_ai-0.5.0/quorus/models/__init__.py +21 -0
- quorus_ai-0.5.0/quorus/models/account.py +118 -0
- quorus_ai-0.5.0/quorus/models/api_key.py +177 -0
- quorus_ai-0.5.0/quorus/models/audit.py +106 -0
- quorus_ai-0.5.0/quorus/models/join_code.py +34 -0
- quorus_ai-0.5.0/quorus/models/outbox.py +92 -0
- quorus_ai-0.5.0/quorus/notifications/__init__.py +11 -0
- quorus_ai-0.5.0/quorus/notifications/agent_events.py +120 -0
- quorus_ai-0.5.0/quorus/notifications/native.py +333 -0
- quorus_ai-0.5.0/quorus/observability/__init__.py +1 -0
- quorus_ai-0.5.0/quorus/observability/redaction.py +65 -0
- quorus_ai-0.5.0/quorus/observability/sentry.py +107 -0
- quorus_ai-0.5.0/quorus/operating_discipline.py +133 -0
- quorus_ai-0.5.0/quorus/private_files.py +39 -0
- quorus_ai-0.5.0/quorus/profiles.py +203 -0
- quorus_ai-0.5.0/quorus/protocol/__init__.py +36 -0
- quorus_ai-0.5.0/quorus/protocol/social_verbs.py +229 -0
- quorus_ai-0.5.0/quorus/relay.py +945 -0
- quorus_ai-0.5.0/quorus/relay_cli.py +64 -0
- quorus_ai-0.5.0/quorus/relay_routes.py +45 -0
- quorus_ai-0.5.0/quorus/retro.py +149 -0
- quorus_ai-0.5.0/quorus/routes/__init__.py +50 -0
- quorus_ai-0.5.0/quorus/routes/admin_dashboard.py +470 -0
- quorus_ai-0.5.0/quorus/routes/admin_metrics.py +243 -0
- quorus_ai-0.5.0/quorus/routes/agent_dm.py +568 -0
- quorus_ai-0.5.0/quorus/routes/agents.py +97 -0
- quorus_ai-0.5.0/quorus/routes/analytics.py +91 -0
- quorus_ai-0.5.0/quorus/routes/approvals.py +247 -0
- quorus_ai-0.5.0/quorus/routes/audit.py +169 -0
- quorus_ai-0.5.0/quorus/routes/bundles.py +112 -0
- quorus_ai-0.5.0/quorus/routes/capabilities.py +229 -0
- quorus_ai-0.5.0/quorus/routes/health.py +97 -0
- quorus_ai-0.5.0/quorus/routes/helpers.py +100 -0
- quorus_ai-0.5.0/quorus/routes/invites.py +187 -0
- quorus_ai-0.5.0/quorus/routes/join_codes.py +351 -0
- quorus_ai-0.5.0/quorus/routes/messages.py +209 -0
- quorus_ai-0.5.0/quorus/routes/models.py +208 -0
- quorus_ai-0.5.0/quorus/routes/persistent_memory.py +329 -0
- quorus_ai-0.5.0/quorus/routes/presence.py +62 -0
- quorus_ai-0.5.0/quorus/routes/room_auth.py +68 -0
- quorus_ai-0.5.0/quorus/routes/room_messages.py +304 -0
- quorus_ai-0.5.0/quorus/routes/room_state.py +442 -0
- quorus_ai-0.5.0/quorus/routes/rooms.py +270 -0
- quorus_ai-0.5.0/quorus/routes/social.py +403 -0
- quorus_ai-0.5.0/quorus/routes/sse.py +146 -0
- quorus_ai-0.5.0/quorus/routes/tool_catalog.py +276 -0
- quorus_ai-0.5.0/quorus/routes/triage.py +482 -0
- quorus_ai-0.5.0/quorus/routes/triage_redis.py +231 -0
- quorus_ai-0.5.0/quorus/routes/usage.py +181 -0
- quorus_ai-0.5.0/quorus/routes/webhooks.py +146 -0
- quorus_ai-0.5.0/quorus/routes/work_queue.py +343 -0
- quorus_ai-0.5.0/quorus/runtime/__init__.py +31 -0
- quorus_ai-0.5.0/quorus/runtime/failover.py +162 -0
- quorus_ai-0.5.0/quorus/runtime/launchd.py +96 -0
- quorus_ai-0.5.0/quorus/runtime/local_relay.py +80 -0
- quorus_ai-0.5.0/quorus/runtime/memory.py +541 -0
- quorus_ai-0.5.0/quorus/runtime/opencode_free.py +68 -0
- quorus_ai-0.5.0/quorus/runtime/review_share.py +93 -0
- quorus_ai-0.5.0/quorus/runtime/supervisor.py +347 -0
- quorus_ai-0.5.0/quorus/runtime/turnguard.py +241 -0
- quorus_ai-0.5.0/quorus/sdk.py +12 -0
- quorus_ai-0.5.0/quorus/services/__init__.py +1 -0
- quorus_ai-0.5.0/quorus/services/analytics_svc.py +27 -0
- quorus_ai-0.5.0/quorus/services/approval_svc.py +261 -0
- quorus_ai-0.5.0/quorus/services/audit_svc.py +435 -0
- quorus_ai-0.5.0/quorus/services/bundle_svc.py +301 -0
- quorus_ai-0.5.0/quorus/services/capability_svc.py +176 -0
- quorus_ai-0.5.0/quorus/services/invite_svc.py +76 -0
- quorus_ai-0.5.0/quorus/services/join_code_svc.py +274 -0
- quorus_ai-0.5.0/quorus/services/message_svc.py +459 -0
- quorus_ai-0.5.0/quorus/services/notification_svc.py +157 -0
- quorus_ai-0.5.0/quorus/services/outbox_svc.py +440 -0
- quorus_ai-0.5.0/quorus/services/p1_persistence.py +195 -0
- quorus_ai-0.5.0/quorus/services/persistent_memory_svc.py +266 -0
- quorus_ai-0.5.0/quorus/services/presence_svc.py +31 -0
- quorus_ai-0.5.0/quorus/services/rate_limit_svc.py +117 -0
- quorus_ai-0.5.0/quorus/services/room_msg_svc.py +391 -0
- quorus_ai-0.5.0/quorus/services/room_svc.py +280 -0
- quorus_ai-0.5.0/quorus/services/social_svc.py +567 -0
- quorus_ai-0.5.0/quorus/services/sse_svc.py +161 -0
- quorus_ai-0.5.0/quorus/services/tool_catalog_svc.py +226 -0
- quorus_ai-0.5.0/quorus/services/webhook_svc.py +664 -0
- quorus_ai-0.5.0/quorus/services/work_queue_svc.py +671 -0
- quorus_ai-0.5.0/quorus/storage/__init__.py +1 -0
- quorus_ai-0.5.0/quorus/storage/base.py +16 -0
- quorus_ai-0.5.0/quorus/storage/postgres.py +114 -0
- quorus_ai-0.5.0/quorus/tui_hub.py +17 -0
- quorus_ai-0.5.0/railway.json +14 -0
- quorus_ai-0.5.0/railway.toml +27 -0
- quorus_ai-0.5.0/render.yaml +38 -0
- quorus_ai-0.5.0/requirements-dev.txt +4 -0
- quorus_ai-0.5.0/requirements.lock +166 -0
- quorus_ai-0.5.0/requirements.txt +5 -0
- quorus_ai-0.5.0/scripts/_mint_aarya.sh +29 -0
- quorus_ai-0.5.0/scripts/autopull.sh +14 -0
- quorus_ai-0.5.0/scripts/cold_install_smoke.py +412 -0
- quorus_ai-0.5.0/scripts/cold_install_smoke.sh +129 -0
- quorus_ai-0.5.0/scripts/demo_reflex.sh +513 -0
- quorus_ai-0.5.0/scripts/demo_wake.sh +281 -0
- quorus_ai-0.5.0/scripts/dogfood.sh +294 -0
- quorus_ai-0.5.0/scripts/e2e_live.py +402 -0
- quorus_ai-0.5.0/scripts/fix_editable_pth.sh +58 -0
- quorus_ai-0.5.0/scripts/heartbeat-local.sh +33 -0
- quorus_ai-0.5.0/scripts/heartbeat.sh +31 -0
- quorus_ai-0.5.0/scripts/install.sh +70 -0
- quorus_ai-0.5.0/scripts/kliment_demo.sh +384 -0
- quorus_ai-0.5.0/scripts/launch_smoke.sh +161 -0
- quorus_ai-0.5.0/scripts/loop.sh +5 -0
- quorus_ai-0.5.0/scripts/patch_entry_points.sh +70 -0
- quorus_ai-0.5.0/scripts/quorus-autosync.sh +83 -0
- quorus_ai-0.5.0/scripts/quorus-coordination.skill +0 -0
- quorus_ai-0.5.0/scripts/quorus_codex_loop.py +396 -0
- quorus_ai-0.5.0/scripts/record_demo_cast.sh +421 -0
- quorus_ai-0.5.0/scripts/record_kliment_cast.sh +219 -0
- quorus_ai-0.5.0/scripts/reflexd.py +4397 -0
- quorus_ai-0.5.0/scripts/reflexd_models.py +321 -0
- quorus_ai-0.5.0/scripts/reflexd_readonly.py +162 -0
- quorus_ai-0.5.0/scripts/reflexd_smoke.sh +108 -0
- quorus_ai-0.5.0/scripts/reflexd_steps.py +191 -0
- quorus_ai-0.5.0/scripts/reflexd_streamb.py +197 -0
- quorus_ai-0.5.0/scripts/reflexd_triage.py +607 -0
- quorus_ai-0.5.0/scripts/reflexd_wake.py +800 -0
- quorus_ai-0.5.0/scripts/rehearse_runbook.sh +249 -0
- quorus_ai-0.5.0/scripts/replay_kliment_cast.sh +55 -0
- quorus_ai-0.5.0/scripts/scenarios.py +559 -0
- quorus_ai-0.5.0/scripts/stall_demo_local.sh +557 -0
- quorus_ai-0.5.0/scripts/stall_install_smoketest.sh +114 -0
- quorus_ai-0.5.0/scripts/stall_setup_aarya.sh +215 -0
- quorus_ai-0.5.0/setup.sh +178 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Murmur Relay — Environment Variables
|
|
2
|
+
# Copy to .env and fill in values, then: docker-compose up
|
|
3
|
+
|
|
4
|
+
# Required: Shared secret for legacy auth (agents without API keys)
|
|
5
|
+
RELAY_SECRET=change-me-to-a-long-random-string
|
|
6
|
+
|
|
7
|
+
# Required: Secret for signing JWTs (min 32 chars)
|
|
8
|
+
JWT_SECRET=change-me-to-a-long-random-secret-min-32-chars
|
|
9
|
+
|
|
10
|
+
# Required: Bootstrap secret for creating the first tenant
|
|
11
|
+
BOOTSTRAP_SECRET=change-me-bootstrap-secret
|
|
12
|
+
|
|
13
|
+
# Optional: Server port (default 8080)
|
|
14
|
+
PORT=8080
|
|
15
|
+
|
|
16
|
+
# Optional: Postgres (defaults to local docker-compose postgres)
|
|
17
|
+
# DATABASE_URL=postgresql+asyncpg://user:pass@host:5432/murmur
|
|
18
|
+
|
|
19
|
+
# Optional: Redis (defaults to local docker-compose redis)
|
|
20
|
+
# REDIS_URL=redis://host:6379/0
|
|
21
|
+
|
|
22
|
+
# Optional: Logging level (DEBUG, INFO, WARNING, ERROR)
|
|
23
|
+
LOG_LEVEL=INFO
|
|
24
|
+
|
|
25
|
+
# Optional: Message limits
|
|
26
|
+
MAX_MESSAGES=1000
|
|
27
|
+
MESSAGE_TTL_SECONDS=86400
|
|
28
|
+
RATE_LIMIT_MAX=60
|
|
29
|
+
MAX_ROOM_MEMBERS=50
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Production environment template
|
|
2
|
+
# Copy to .env.prod and fill in values
|
|
3
|
+
|
|
4
|
+
# Required secrets (generate with: openssl rand -hex 32)
|
|
5
|
+
JWT_SECRET=your-jwt-secret-min-32-chars-here
|
|
6
|
+
BOOTSTRAP_SECRET=your-bootstrap-secret-here
|
|
7
|
+
RELAY_SECRET=your-relay-secret-here
|
|
8
|
+
POSTGRES_PASSWORD=your-strong-postgres-password
|
|
9
|
+
REDIS_PASSWORD=your-strong-redis-password
|
|
10
|
+
|
|
11
|
+
# Optional: Redis memory limit (default 512mb)
|
|
12
|
+
# REDIS_MAXMEMORY=1gb
|
|
13
|
+
|
|
14
|
+
# Optional: Relay settings
|
|
15
|
+
# PORT=8080
|
|
16
|
+
# LOG_LEVEL=WARNING
|
|
17
|
+
# MESSAGE_TTL_SECONDS=86400
|
|
18
|
+
# VISIBILITY_TIMEOUT_SECONDS=60
|
|
19
|
+
# IDEMPOTENCY_TTL_SECONDS=300
|
|
20
|
+
# RATE_LIMIT_WINDOW=60
|
|
21
|
+
# RATE_LIMIT_MAX=60
|
|
22
|
+
|
|
23
|
+
# Sentry — set in production via `flyctl secrets set SENTRY_DSN=...`.
|
|
24
|
+
# Leave unset locally; init_sentry() is a no-op without a DSN.
|
|
25
|
+
# SENTRY_DSN=
|
|
26
|
+
# SENTRY_TRACES_SAMPLE_RATE=0.05
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*.pyo
|
|
4
|
+
*.egg-info/
|
|
5
|
+
dist/
|
|
6
|
+
build/
|
|
7
|
+
.eggs/
|
|
8
|
+
.pytest_cache/
|
|
9
|
+
.ruff_cache/
|
|
10
|
+
.venv/
|
|
11
|
+
.env
|
|
12
|
+
messages.json
|
|
13
|
+
.claude/
|
|
14
|
+
uv.lock
|
|
15
|
+
.DS_Store
|
|
16
|
+
ROADMAP.md
|
|
17
|
+
docs/launch/
|
|
18
|
+
.mcp.json
|
|
19
|
+
.murmur/
|
|
20
|
+
.vercel
|
|
21
|
+
*.mcp.*.json
|
|
22
|
+
website/vite.config.d.ts
|
|
23
|
+
website/vite.config.js
|
|
24
|
+
website/*.tsbuildinfo
|
|
25
|
+
MagicMock/
|
|
26
|
+
|
|
27
|
+
# Graphify local knowledge graph (do not commit)
|
|
28
|
+
# Share only the readable graph report and page; rebuild the rest with `graphify update .`
|
|
29
|
+
graphify-out/*
|
|
30
|
+
!graphify-out/GRAPH_REPORT.md
|
|
31
|
+
!graphify-out/graph.html
|
|
32
|
+
.graphify/
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# --- generated by the graphify sweep, 2026-08-28 ---
|
|
2
|
+
# Mirrors Rokan's .graphifyignore. The secrets block at the bottom matters
|
|
3
|
+
# only once a semantic pass runs: the free AST pass reads symbol names,
|
|
4
|
+
# but a semantic pass reads file CONTENT and sends it to a model.
|
|
5
|
+
|
|
6
|
+
# Design assets (not code)
|
|
7
|
+
design/
|
|
8
|
+
*.html
|
|
9
|
+
*.pdf
|
|
10
|
+
*.png
|
|
11
|
+
*.jpg
|
|
12
|
+
*.jpeg
|
|
13
|
+
*.svg
|
|
14
|
+
*.gif
|
|
15
|
+
*.mp4
|
|
16
|
+
*.mov
|
|
17
|
+
|
|
18
|
+
# Dependencies
|
|
19
|
+
node_modules/
|
|
20
|
+
__pycache__/
|
|
21
|
+
.venv/
|
|
22
|
+
venv/
|
|
23
|
+
target/
|
|
24
|
+
Pods/
|
|
25
|
+
vendor/
|
|
26
|
+
|
|
27
|
+
# Build outputs
|
|
28
|
+
dist/
|
|
29
|
+
build/
|
|
30
|
+
.next/
|
|
31
|
+
.expo/
|
|
32
|
+
out/
|
|
33
|
+
DerivedData/
|
|
34
|
+
|
|
35
|
+
# Lock files
|
|
36
|
+
package-lock.json
|
|
37
|
+
yarn.lock
|
|
38
|
+
pnpm-lock.yaml
|
|
39
|
+
Cargo.lock
|
|
40
|
+
Podfile.lock
|
|
41
|
+
poetry.lock
|
|
42
|
+
uv.lock
|
|
43
|
+
|
|
44
|
+
# Generated
|
|
45
|
+
*.tsbuildinfo
|
|
46
|
+
*.generated.ts
|
|
47
|
+
*.generated.js
|
|
48
|
+
*.pb.go
|
|
49
|
+
*_pb2.py
|
|
50
|
+
|
|
51
|
+
# Test fixtures (boilerplate, low signal)
|
|
52
|
+
**/__fixtures__/
|
|
53
|
+
**/fixtures/
|
|
54
|
+
**/snapshots/
|
|
55
|
+
|
|
56
|
+
# Cache
|
|
57
|
+
.cache/
|
|
58
|
+
.parcel-cache/
|
|
59
|
+
.pytest_cache/
|
|
60
|
+
.mypy_cache/
|
|
61
|
+
.ruff_cache/
|
|
62
|
+
|
|
63
|
+
# Git
|
|
64
|
+
.git/
|
|
65
|
+
|
|
66
|
+
# Scratch
|
|
67
|
+
memory/
|
|
68
|
+
scratch/
|
|
69
|
+
experiments/
|
|
70
|
+
tmp/
|
|
71
|
+
|
|
72
|
+
# --- secrets and credentials: never into a graph, never to a model ---
|
|
73
|
+
.env
|
|
74
|
+
.env.*
|
|
75
|
+
*.pem
|
|
76
|
+
*.key
|
|
77
|
+
*.p12
|
|
78
|
+
*.keystore
|
|
79
|
+
*.jks
|
|
80
|
+
*.mobileprovision
|
|
81
|
+
secrets/
|
|
82
|
+
credentials/
|
|
83
|
+
*credentials*.json
|
|
84
|
+
service-account*.json
|
|
85
|
+
GoogleService-Info.plist
|
|
86
|
+
google-services.json
|
|
87
|
+
*.sqlite
|
|
88
|
+
*.db
|
|
89
|
+
|
|
90
|
+
# --- patient / personal data, by convention ---
|
|
91
|
+
# No real PHI is believed to live in these repos. Listed anyway, because a
|
|
92
|
+
# convention only protects you if it predates the file that needs it.
|
|
93
|
+
phi/
|
|
94
|
+
patient_data/
|
|
95
|
+
*patients*.csv
|
|
96
|
+
*patients*.json
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
Read CLAUDE.md: it holds the project rules, test and lint commands for every agent.
|
|
4
|
+
|
|
5
|
+
The essentials, for tools that don't read CLAUDE.md:
|
|
6
|
+
|
|
7
|
+
- Python lives in `~/dev/Quorus/.venv`. Don't look for another one, and never
|
|
8
|
+
search the whole disk (`find /`) to find it.
|
|
9
|
+
- Tests, from an agent worktree:
|
|
10
|
+
`PYTHONPATH=.:packages/cli:packages/mcp:packages/sdk:packages/tui ~/dev/Quorus/.venv/bin/python -m pytest -q -x <test files>`
|
|
11
|
+
- Run only the test files you touched; the laptop is shared, so no full-suite
|
|
12
|
+
runs unless you're asked to.
|
|
13
|
+
- Lint: `~/dev/Quorus/.venv/bin/ruff check .`
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to Quorus are documented here. This project follows
|
|
4
|
+
[Semantic Versioning](https://semver.org/) and [Keep a Changelog](https://keepachangelog.com/).
|
|
5
|
+
|
|
6
|
+
## [Unreleased]
|
|
7
|
+
|
|
8
|
+
## [0.5.0] — 2026-10-17
|
|
9
|
+
|
|
10
|
+
First PyPI release, as `quorus-ai` (`pipx install quorus-ai`; the command is still `quorus`).
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Any model.** `quorus agent add opencode --model <provider/model>` runs any model
|
|
15
|
+
opencode supports: free open-source models (DeepSeek, Qwen), OpenRouter, local Ollama.
|
|
16
|
+
`quorus agent add gemini` runs Gemini CLI (needs a free AI Studio API key). They get the
|
|
17
|
+
same room tools, permission modes and session memory as Claude Code and Codex.
|
|
18
|
+
- **As many agents as you want.** `--name backend` adds `<you>-backend-claude` next to
|
|
19
|
+
`<you>-claude`. `--model` picks the model for any tool.
|
|
20
|
+
- **Every agent answers you.** A human message wakes every agent in the room; agent chatter
|
|
21
|
+
still picks one.
|
|
22
|
+
- **Team lead.** `quorus agent add claude --room R --lead`: the lead splits your request
|
|
23
|
+
into tasks and assigns them, the others answer briefly and wait for an assignment,
|
|
24
|
+
results flow back to the lead, and it tells you when everything is done.
|
|
25
|
+
- **Notifications that reach you.** Your agents ping your desktop when they ship to main,
|
|
26
|
+
ask you something, or get stuck, even with Quorus closed (`QUORUS_NOTIFY=0` to mute).
|
|
27
|
+
- **See who is working.** `⋯ @you-claude working 1m 20s` in the chat while a wake runs.
|
|
28
|
+
- **Catch up.** The home screen shows what shipped, who needs you and who is stuck since
|
|
29
|
+
you last opened Quorus.
|
|
30
|
+
- **Readable chat.** Agent markdown (bold, code, bullets, headings) renders as clean text.
|
|
31
|
+
- Warnings before adding an agent that can't wake (no Gemini key, Ollama not running or
|
|
32
|
+
missing the model).
|
|
33
|
+
|
|
34
|
+
### Fixed
|
|
35
|
+
|
|
36
|
+
- opencode agents wrote files into the daemon's working directory instead of the repo, and
|
|
37
|
+
manual (read-only) rooms weren't read-only on opencode 2.x.
|
|
38
|
+
- A project's own `opencode.json` could point an agent's room tools at the wrong relay.
|
|
39
|
+
- Codex couldn't post to the room itself: its MCP calls needed an approval nobody could give,
|
|
40
|
+
and a stale `quorus` entry in `~/.codex/config.toml` overrode the agent's identity.
|
|
41
|
+
- Agents committed generated files (`__pycache__`, `.pyc`) to your main branch.
|
|
42
|
+
- Each agent now logs to its own file; a second Ctrl-C no longer prints a traceback.
|
|
43
|
+
- Gemini agents failed on any machine with an old Google login in `~/.gemini`; each Gemini
|
|
44
|
+
agent now gets its own Gemini home and signs in with your API key.
|
|
45
|
+
- `quorus agent remove` crashed on Linux and `quorus agent list` showed nothing there.
|
|
46
|
+
- opencode 1.x (still what `npm i -g opencode-ai` installs) failed every wake.
|
|
47
|
+
|
|
48
|
+
## [0.4.0] — 2026-10-10
|
|
49
|
+
|
|
50
|
+
Never published to PyPI.
|
|
51
|
+
|
|
52
|
+
### Added
|
|
53
|
+
|
|
54
|
+
- **Agents that wake on their own.** `quorus agent add claude|codex --room R [--repo P]`
|
|
55
|
+
starts a background agent that wakes when the room needs it, works in its own git
|
|
56
|
+
worktree, publishes to your repo's main branch, and asks a teammate to review.
|
|
57
|
+
- **The agent decides whether to answer.** Every message not addressed to someone else
|
|
58
|
+
wakes one agent, chosen by auction. It answers, or replies `NO_REPLY` to stay quiet.
|
|
59
|
+
Unaddressed agent chatter stops after 6 agent messages in a row.
|
|
60
|
+
- **Permission modes per room:** `--mode default|manual|autonomous`. Manual asks you
|
|
61
|
+
before risky actions (`quorus approvals`, `quorus approve <id>`).
|
|
62
|
+
- **First run just works:** `quorus` with no config sets up a local relay with a generated
|
|
63
|
+
secret, or joins a teammate's relay from an invite.
|
|
64
|
+
- `quorus agent list|remove`, `quorus --version`, readable errors with exit codes
|
|
65
|
+
(2 unreachable, 3 auth, 4 not found, 5 refused).
|
|
66
|
+
|
|
67
|
+
### Known limits
|
|
68
|
+
|
|
69
|
+
- No hosted relay yet: teammates must reach your relay's address.
|
|
70
|
+
- On a shared-secret relay, manual-mode approvals and kicks are advisory. Use account
|
|
71
|
+
mode for real separation.
|
|
72
|
+
- The background agent uses launchd on macOS and a detached process elsewhere.
|
|
73
|
+
|
|
74
|
+
### Earlier work included in 0.4.0
|
|
75
|
+
|
|
76
|
+
### Added — Wave 9 (TUI)
|
|
77
|
+
|
|
78
|
+
- **Work-queue panel** — `Ctrl-W` toggles a fold-up panel above the chat
|
|
79
|
+
feed showing every active task in the current room (`task_id`,
|
|
80
|
+
`claimed_by`, `status`, `started_at`, `eta`). Refetches from
|
|
81
|
+
`GET /v1/work_queue/{room_id}` on open; cached for 30 s so rapid
|
|
82
|
+
toggles don't hammer the relay.
|
|
83
|
+
- **Agent-DM inbox** — `Ctrl-N` (originally `Ctrl-D` in the spec, but
|
|
84
|
+
`Ctrl-D` already binds to QUIT in the TUI input loop and `Ctrl-I`
|
|
85
|
+
shadows Tab; `Ctrl-N` for "Notifications/iNbox" was free of all
|
|
86
|
+
collisions) toggles an iMessage-style preview of the last 8 agent
|
|
87
|
+
DMs. A dedicated background thread subscribes to
|
|
88
|
+
`/stream/dm/{participant}` and appends events into a bounded deque.
|
|
89
|
+
- **Threaded replies** — when any message in the feed carries
|
|
90
|
+
`thread_root_id`, `render_bubble_feed` now reorders so children
|
|
91
|
+
render directly under their root with a `└─` connector and 5-cell
|
|
92
|
+
left indent. Threads default to **collapsed** (a 1-line
|
|
93
|
+
`@sender: snippet · N replies (/expand <id>)` rollup); the new
|
|
94
|
+
`/expand <root_id|all>` slash command flips an entry to expanded.
|
|
95
|
+
|
|
96
|
+
Public beta launch. Full rebrand from Murmur, coordination-layer positioning.
|
|
97
|
+
|
|
98
|
+
### Added
|
|
99
|
+
|
|
100
|
+
- **Rebrand to Quorus** across package name, CLI entry (`quorus`), config dir
|
|
101
|
+
(`~/.quorus/`), API key prefix (`quorus_sk_`), join token prefix
|
|
102
|
+
(`quorus_join_`), and MCP server name.
|
|
103
|
+
- New `quorus-mcp` console entry point — matches the MCP snippet shown on the
|
|
104
|
+
website so `"command": "quorus-mcp"` works after install.
|
|
105
|
+
- First-class Windsurf integration: `quorus connect windsurf` emits MCP
|
|
106
|
+
config for `~/.codeium/windsurf/mcp_config.json`.
|
|
107
|
+
- `quorus init --config-dir PATH` flag for multi-profile setups (also honors
|
|
108
|
+
`$QUORUS_CONFIG_DIR`).
|
|
109
|
+
- Open Graph / Twitter Card social metadata + `og.svg` on the marketing site.
|
|
110
|
+
- `CHANGELOG.md` (this file), `sitemap.xml`, and `robots.txt` for launch
|
|
111
|
+
hygiene.
|
|
112
|
+
- Copyable one-line install command visible on the website hero.
|
|
113
|
+
- Relay prints a human-friendly listen banner on startup.
|
|
114
|
+
|
|
115
|
+
### Changed
|
|
116
|
+
|
|
117
|
+
- **Default `USE_OUTBOX=true`** — fan-out goes through the durable outbox by
|
|
118
|
+
default; silent message loss on Redis hiccups is gone.
|
|
119
|
+
- Audit service exceptions propagate (per CLAUDE.md Lessons Learned). Callers
|
|
120
|
+
wrap business + audit writes in a single transaction.
|
|
121
|
+
- `audit_svc.record()` and `record_batch()` accept an optional `session`
|
|
122
|
+
param so outbox/room writers thread their transaction through — no more
|
|
123
|
+
nested-session split-brain ledger.
|
|
124
|
+
- Content-Security-Policy tightened: no more `'unsafe-inline'` on
|
|
125
|
+
`script-src`; added `base-uri`, `form-action`, `img-src data:`.
|
|
126
|
+
- SSE token mint binds `recipient` to the caller identity; legacy auth
|
|
127
|
+
without admin role can no longer mint tokens for arbitrary recipients.
|
|
128
|
+
- JWT decode errors now log the reason (`ExpiredSignatureError` /
|
|
129
|
+
`InvalidTokenError`) instead of silently falling through.
|
|
130
|
+
- 404 rate limiter's in-memory dicts are guarded by `asyncio.Lock` — no more
|
|
131
|
+
read-modify-write races under 404 floods.
|
|
132
|
+
- Doctor separates required vs optional checks (`11/11 required · 0/1
|
|
133
|
+
optional`) so the opt-in hook doesn't read as failure.
|
|
134
|
+
- Website: removed unverified "sub-100ms latency" claim, Copilot logo (no
|
|
135
|
+
real MCP path), stale "6+ platforms" (now honest 5), and CTA `870+ tests`
|
|
136
|
+
pill. `quorus-ai` → `quorus` everywhere.
|
|
137
|
+
- `render.yaml` wires JWT_SECRET, BOOTSTRAP_SECRET, DATABASE_URL, REDIS_URL,
|
|
138
|
+
USE_OUTBOX, ALLOW_LEGACY_AUTH, CORS_ORIGINS.
|
|
139
|
+
|
|
140
|
+
### Fixed
|
|
141
|
+
|
|
142
|
+
- `/v1/usage` 500 crash for non-admins (`list_by_member` → `list_for_member`).
|
|
143
|
+
- Cursor + Gemini `quorus connect` commands emitted MCP configs pointing at a
|
|
144
|
+
nonexistent path; now emit `"command": "quorus-mcp"`.
|
|
145
|
+
- `quorus join <quorus_join_...>` previously rejected new-prefix tokens; now
|
|
146
|
+
accepts both `quorus_join_` and legacy `murm_join_`.
|
|
147
|
+
- Config file TOCTOU race — now `os.open(..., 0o600)` atomic write.
|
|
148
|
+
- Hero particle canvas respects `prefers-reduced-motion` and pauses when
|
|
149
|
+
off-screen (battery + INP).
|
|
150
|
+
- Waitlist emails: rebrand sender defaults to `@quorus.dev`, use `waitUntil`
|
|
151
|
+
so Vercel serverless doesn't freeze before send completes.
|
|
152
|
+
- Footer anchor `#howit` pointed at a non-rendered section; now `#architecture`.
|
|
153
|
+
- AgentShowcase branding banner: MURMUR → QUORUS.
|
|
154
|
+
- TUI guard against `selected is None` crash on fresh install.
|
|
155
|
+
- Vite sourcemaps no longer shipped as public `.map` files.
|
|
156
|
+
|
|
157
|
+
### Security
|
|
158
|
+
|
|
159
|
+
- See `Changed` above for CSP, SSE-binding, JWT logging, and 404 race fixes.
|
|
160
|
+
- Four critical items fixed this cycle: osascript injection in watcher,
|
|
161
|
+
agent-name shell injection in spawn, bootstrap-secret timing attack
|
|
162
|
+
(`hmac.compare_digest`), config-write TOCTOU.
|
|
163
|
+
- IP rate limits added to invite-join (10/min) and admin tenant creation
|
|
164
|
+
(5/min).
|
|
165
|
+
- Invite page template values are `html.escape`d.
|
|
166
|
+
|
|
167
|
+
### Known limitations (beta-framed)
|
|
168
|
+
|
|
169
|
+
- Not on PyPI yet — install via `pipx install "quorus @ git+..."`.
|
|
170
|
+
- Load/chaos tests not yet run. Concurrency envelope unknown.
|
|
171
|
+
- Webhook egress relies on app-level private-IP blocklist (no network-level
|
|
172
|
+
proxy).
|
|
173
|
+
- Admin tooling for DLQ replay and tenant suspension is CLI-only.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## [0.3.0] — 2026-04-13 (pre-rebrand, Murmur)
|
|
178
|
+
|
|
179
|
+
- Monorepo split into packages/sdk, packages/cli, packages/mcp, packages/tui.
|
|
180
|
+
- Transactional outbox pattern (optional, `USE_OUTBOX=true`).
|
|
181
|
+
- Audit ledger with `/v1/audit/*` endpoints.
|
|
182
|
+
- Account-based identity — `participant_id` in JWT claims + FK columns.
|
|
183
|
+
|
|
184
|
+
## [0.2.x] — earlier (pre-outbox)
|
|
185
|
+
|
|
186
|
+
See git history.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# CLAUDE.md — Quorus
|
|
2
|
+
|
|
3
|
+
## Shared Context Protocol
|
|
4
|
+
|
|
5
|
+
**Read `docs/internal/CONTEXT.md` at the start of every session.** It contains the current project state, what's in progress, recent changes, architectural decisions, and next priorities. It is the shared memory between all contributors' Claude instances.
|
|
6
|
+
|
|
7
|
+
**Update `docs/internal/CONTEXT.md` after every significant change:**
|
|
8
|
+
|
|
9
|
+
- Add your changes to "Recent Changes" (keep last 10, drop oldest)
|
|
10
|
+
- Update "In Progress" when starting/finishing work
|
|
11
|
+
- Update "Current State" if the system's capabilities changed
|
|
12
|
+
- Add to "Decisions Made" when architectural choices are made
|
|
13
|
+
- Update "Next Up" when priorities shift
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Project
|
|
18
|
+
|
|
19
|
+
Quorus — coordination layer for AI agent swarms. Real-time rooms, messaging, distributed locks.
|
|
20
|
+
|
|
21
|
+
**Stack:** Python 3.10+, FastAPI, asyncio, httpx, mcp (FastMCP), pytest, ruff, rich
|
|
22
|
+
|
|
23
|
+
**Run tests:** `pytest -v`
|
|
24
|
+
**From an agent worktree** (no venv of its own): `PYTHONPATH=.:packages/cli:packages/mcp:packages/sdk:packages/tui ~/dev/Quorus/.venv/bin/python -m pytest -q`
|
|
25
|
+
**Lint:** `ruff check .`
|
|
26
|
+
**Lint fix:** `ruff check . --fix`
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Architecture
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
Claude Code A -> MCP Server (stdio) -> HTTP -> [Quorus Relay (FastAPI)] -> HTTP -> MCP Server (stdio) -> Claude Code B
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
- `quorus/relay.py` — Central relay (FastAPI). Rooms, SSE fan-out, persistence, rate limiting.
|
|
37
|
+
- `quorus_mcp/server.py` — MCP server. 12 tools for coordination.
|
|
38
|
+
- `quorus/config.py` — Config loading. Priority: env vars > ~/.quorus/config.json > legacy fallback.
|
|
39
|
+
- `quorus_cli/cli.py` — CLI commands. `quorus` opens TUI by default.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Rules
|
|
44
|
+
|
|
45
|
+
- Files under 500 lines. Split if larger.
|
|
46
|
+
- Async-first. Use `asyncio.to_thread` for blocking I/O.
|
|
47
|
+
- All external input validated before use.
|
|
48
|
+
- Never log secrets or tokens.
|
|
49
|
+
- Tests required for new features and bug fixes.
|
|
50
|
+
- Conventional commits, under 50 chars, imperative mood.
|
|
51
|
+
|
|
52
|
+
## graphify
|
|
53
|
+
|
|
54
|
+
This project has a graphify knowledge graph at graphify-out/.
|
|
55
|
+
|
|
56
|
+
Rules:
|
|
57
|
+
- Before answering architecture or codebase questions, read graphify-out/GRAPH_REPORT.md for god nodes and community structure
|
|
58
|
+
- If graphify-out/wiki/index.md exists, navigate it instead of reading raw files
|
|
59
|
+
- After modifying code files in this session, run `graphify update .` to keep the graph current (AST-only, no API cost)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Contributing to Murmur
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in contributing to Murmur!
|
|
4
|
+
|
|
5
|
+
## Development Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
git clone https://github.com/Quorus-dev/Quorus.git
|
|
9
|
+
cd Quorus
|
|
10
|
+
python3 -m venv .venv && source .venv/bin/activate
|
|
11
|
+
pip install -e ".[dev]" -e packages/sdk -e packages/cli -e packages/mcp -e packages/tui
|
|
12
|
+
# macOS only: undo a hatchling-editable + Python 3.14 + macOS interaction
|
|
13
|
+
# that hides .pth files via com.apple.provenance + UF_HIDDEN. Idempotent.
|
|
14
|
+
bash scripts/fix_editable_pth.sh
|
|
15
|
+
python -c "import quorus, quorus_sdk, quorus_cli, quorus_mcp, quorus_tui" # must print nothing
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Running Tests
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pytest -v
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Running the E2E Test
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
python scripts/e2e_live.py
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Code Standards
|
|
31
|
+
|
|
32
|
+
- Python 3.10+, async-first
|
|
33
|
+
- Ruff for linting: `ruff check .`
|
|
34
|
+
- Max 100 char lines, files under 500 lines
|
|
35
|
+
- All external input validated before use
|
|
36
|
+
- Never log secrets or tokens
|
|
37
|
+
- Tests required for new features and bug fixes
|
|
38
|
+
|
|
39
|
+
## Commit Conventions
|
|
40
|
+
|
|
41
|
+
- Conventional commits: `feat:`, `fix:`, `refactor:`, `test:`, `docs:`, `chore:`
|
|
42
|
+
- Under 50 chars, imperative mood
|
|
43
|
+
- One logical change per commit
|
|
44
|
+
|
|
45
|
+
## Submitting Changes
|
|
46
|
+
|
|
47
|
+
1. Fork the repo and create a branch
|
|
48
|
+
2. Make your changes with tests
|
|
49
|
+
3. Run `ruff check .` and `pytest -v`
|
|
50
|
+
4. Submit a pull request
|
|
51
|
+
|
|
52
|
+
## Architecture
|
|
53
|
+
|
|
54
|
+
See `docs/internal/CONTEXT.md` for current architecture and design decisions.
|
|
55
|
+
|
|
56
|
+
## License
|
|
57
|
+
|
|
58
|
+
By contributing, you agree that your contributions will be licensed under the MIT License.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# syntax=docker/dockerfile:1.7
|
|
2
|
+
# ---------------------------------------------------------------------------
|
|
3
|
+
# Stage 1 — builder: install pinned dependencies + build the wheel.
|
|
4
|
+
# Ships pip + build deps + cached wheels.
|
|
5
|
+
# ---------------------------------------------------------------------------
|
|
6
|
+
FROM python:3.12-slim AS builder
|
|
7
|
+
|
|
8
|
+
WORKDIR /build
|
|
9
|
+
|
|
10
|
+
# Build deps + uv (10x faster pip resolver, deterministic locks).
|
|
11
|
+
ENV PIP_NO_CACHE_DIR=1 \
|
|
12
|
+
PIP_DISABLE_PIP_VERSION_CHECK=1 \
|
|
13
|
+
PYTHONDONTWRITEBYTECODE=1
|
|
14
|
+
|
|
15
|
+
# Install into an isolated prefix so we can copy the resolved tree forward
|
|
16
|
+
# into the runtime stage without dragging pip / wheels along with it.
|
|
17
|
+
ENV PREFIX=/install
|
|
18
|
+
RUN mkdir -p "$PREFIX"
|
|
19
|
+
|
|
20
|
+
# Pinned deps from the lockfile (single source of truth — see pyproject.toml
|
|
21
|
+
# header). The lockfile must be regenerated via ``uv pip compile`` whenever
|
|
22
|
+
# pyproject.toml changes. Both files commit in the same PR.
|
|
23
|
+
COPY requirements.lock ./
|
|
24
|
+
RUN pip install --no-cache-dir --prefix="$PREFIX" -r requirements.lock
|
|
25
|
+
|
|
26
|
+
# Source layout: hatchling's wheel pulls every package listed in
|
|
27
|
+
# [tool.hatch.build.targets.wheel].packages — quorus/ + packages/* monorepo.
|
|
28
|
+
COPY pyproject.toml README.md alembic.ini ./
|
|
29
|
+
COPY quorus/ quorus/
|
|
30
|
+
COPY packages/ packages/
|
|
31
|
+
|
|
32
|
+
# Install Quorus itself (no deps — those came from the lockfile above).
|
|
33
|
+
RUN pip install --no-cache-dir --prefix="$PREFIX" --no-deps .
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# ---------------------------------------------------------------------------
|
|
37
|
+
# Stage 2 — runtime: lean image, no pip / build deps / wheel cache.
|
|
38
|
+
# ---------------------------------------------------------------------------
|
|
39
|
+
FROM python:3.12-slim AS runtime
|
|
40
|
+
|
|
41
|
+
WORKDIR /app
|
|
42
|
+
|
|
43
|
+
# Carry the resolved Python install forward; pip itself is left behind.
|
|
44
|
+
COPY --from=builder /install /usr/local
|
|
45
|
+
# Fly release_command runs from /app, so Alembic's config and migration
|
|
46
|
+
# scripts must exist outside the installed wheel.
|
|
47
|
+
COPY --from=builder /build/alembic.ini /app/alembic.ini
|
|
48
|
+
COPY --from=builder /build/quorus/migrations /app/quorus/migrations
|
|
49
|
+
|
|
50
|
+
# Non-root user for security. Match the data dir's UID so volumes mounted
|
|
51
|
+
# with the default UID:GID (1000:1000) work without a bind-mount chown.
|
|
52
|
+
RUN useradd --create-home --shell /bin/bash --uid 1000 quorus \
|
|
53
|
+
&& mkdir -p /app/data \
|
|
54
|
+
&& chown -R quorus:quorus /app/data
|
|
55
|
+
|
|
56
|
+
USER quorus
|
|
57
|
+
|
|
58
|
+
# Persist messages across restarts (fallback when Postgres unavailable).
|
|
59
|
+
VOLUME ["/app/data"]
|
|
60
|
+
ENV MESSAGES_FILE=/app/data/messages.json
|
|
61
|
+
|
|
62
|
+
EXPOSE 8080
|
|
63
|
+
ENV PORT=8080 \
|
|
64
|
+
PYTHONDONTWRITEBYTECODE=1 \
|
|
65
|
+
PYTHONUNBUFFERED=1
|
|
66
|
+
|
|
67
|
+
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
|
|
68
|
+
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8080/health')"
|
|
69
|
+
|
|
70
|
+
CMD python -m uvicorn quorus.relay:app --host 0.0.0.0 --port ${PORT:-8080}
|
quorus_ai-0.5.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Arav Kekane, Aarya
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|