nexor-agora 0.1.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.
Files changed (46) hide show
  1. nexor_agora-0.1.0/.env.example +27 -0
  2. nexor_agora-0.1.0/.github/ISSUE_TEMPLATE/bug_report.md +23 -0
  3. nexor_agora-0.1.0/.github/ISSUE_TEMPLATE/feature_request.md +17 -0
  4. nexor_agora-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +12 -0
  5. nexor_agora-0.1.0/.github/workflows/ci.yml +62 -0
  6. nexor_agora-0.1.0/.github/workflows/release.yml +47 -0
  7. nexor_agora-0.1.0/.gitignore +9 -0
  8. nexor_agora-0.1.0/CHANGELOG.md +68 -0
  9. nexor_agora-0.1.0/CODE_OF_CONDUCT.md +16 -0
  10. nexor_agora-0.1.0/CONTRIBUTING.md +52 -0
  11. nexor_agora-0.1.0/Dockerfile +20 -0
  12. nexor_agora-0.1.0/LICENSE +21 -0
  13. nexor_agora-0.1.0/Makefile +40 -0
  14. nexor_agora-0.1.0/PKG-INFO +265 -0
  15. nexor_agora-0.1.0/README.md +235 -0
  16. nexor_agora-0.1.0/RESEARCH.md +81 -0
  17. nexor_agora-0.1.0/SECURITY.md +35 -0
  18. nexor_agora-0.1.0/SETUP.md +89 -0
  19. nexor_agora-0.1.0/docker-compose.yml +47 -0
  20. nexor_agora-0.1.0/docs/rfc-001-plans-and-tasks.md +271 -0
  21. nexor_agora-0.1.0/docs/rfc-002-live-mode.md +132 -0
  22. nexor_agora-0.1.0/examples/nexor-agora-mcp.example.json +15 -0
  23. nexor_agora-0.1.0/pyproject.toml +55 -0
  24. nexor_agora-0.1.0/scripts/check_no_org_leak.sh +26 -0
  25. nexor_agora-0.1.0/src/nexor_agora/__init__.py +13 -0
  26. nexor_agora-0.1.0/src/nexor_agora/__main__.py +8 -0
  27. nexor_agora-0.1.0/src/nexor_agora/app.py +920 -0
  28. nexor_agora-0.1.0/src/nexor_agora/auth.py +62 -0
  29. nexor_agora-0.1.0/src/nexor_agora/cli.py +44 -0
  30. nexor_agora-0.1.0/src/nexor_agora/config.py +80 -0
  31. nexor_agora-0.1.0/src/nexor_agora/db.py +197 -0
  32. nexor_agora-0.1.0/src/nexor_agora/events.py +42 -0
  33. nexor_agora-0.1.0/src/nexor_agora/mcp_server.py +856 -0
  34. nexor_agora-0.1.0/src/nexor_agora/mentions.py +28 -0
  35. nexor_agora-0.1.0/src/nexor_agora/models.py +261 -0
  36. nexor_agora-0.1.0/src/nexor_agora/notify.py +74 -0
  37. nexor_agora-0.1.0/src/nexor_agora/plans.py +84 -0
  38. nexor_agora-0.1.0/src/nexor_agora/privacy.py +52 -0
  39. nexor_agora-0.1.0/src/nexor_agora/serve.py +17 -0
  40. nexor_agora-0.1.0/src/nexor_agora/static/index.html +769 -0
  41. nexor_agora-0.1.0/src/nexor_agora/store.py +1076 -0
  42. nexor_agora-0.1.0/tests/test_integration.py +317 -0
  43. nexor_agora-0.1.0/tests/test_live.py +87 -0
  44. nexor_agora-0.1.0/tests/test_mentions.py +57 -0
  45. nexor_agora-0.1.0/tests/test_plans.py +74 -0
  46. nexor_agora-0.1.0/tests/test_privacy.py +37 -0
@@ -0,0 +1,27 @@
1
+ # Copy to .env and edit. Only the hub host needs these.
2
+
3
+ # Public URL of the hub (used in notification deep links).
4
+ NEXOR_AGORA_PUBLIC_URL=http://localhost:8400
5
+ NEXOR_AGORA_PORT=8400
6
+
7
+ # Database password for the dedicated nexor_agora Postgres role.
8
+ NEXOR_AGORA_DB_PASSWORD=change-me
9
+
10
+ # LAN trust: true lets anyone register. Set false + an admin key to gate it.
11
+ NEXOR_AGORA_OPEN_REGISTRATION=true
12
+ NEXOR_AGORA_ADMIN_KEY=
13
+ # Reject any message whose body looks like it contains a secret/credential.
14
+ NEXOR_AGORA_BLOCK_SECRETS=true
15
+
16
+ # --- Notifications (optional, outbound only) ------------------------------
17
+ # Telegram bot token (from @BotFather) used to deliver escalations/mentions.
18
+ NEXOR_AGORA_TELEGRAM_BOT_TOKEN=
19
+ # Slack incoming webhook for the shared team channel.
20
+ NEXOR_AGORA_SLACK_WEBHOOK_URL=
21
+
22
+ # CORS origins for the web UI (comma-separated, or * on a trusted LAN).
23
+ NEXOR_AGORA_CORS_ORIGINS=*
24
+
25
+ # NOTE: agent-runner settings (MCP isolation, per-conversation budget, turn caps)
26
+ # are NOT hub config — the hub never runs an agent. They belong to the external
27
+ # runner that connects to this hub over its public API.
@@ -0,0 +1,23 @@
1
+ ---
2
+ name: Bug report
3
+ about: Something isn't working as expected
4
+ title: "[bug] "
5
+ labels: bug
6
+ ---
7
+
8
+ **What happened**
9
+ A clear description of the bug.
10
+
11
+ **To reproduce**
12
+ Steps / commands. Include relevant config (redact secrets).
13
+
14
+ **Expected behavior**
15
+
16
+ **Environment**
17
+ - nexor-agora version / commit:
18
+ - How you run it (Docker / pip):
19
+ - Python version:
20
+ - Postgres version:
21
+
22
+ **Logs**
23
+ Relevant hub / `nexor-agora agent` logs (redact secrets).
@@ -0,0 +1,17 @@
1
+ ---
2
+ name: Feature request
3
+ about: Suggest an idea or improvement
4
+ title: "[feat] "
5
+ labels: enhancement
6
+ ---
7
+
8
+ **Problem / motivation**
9
+ What are you trying to do? What's painful today?
10
+
11
+ **Proposed solution**
12
+ What would you like to happen?
13
+
14
+ **Alternatives considered**
15
+
16
+ **Additional context**
17
+ Notes, mockups, links. Does it affect the privacy/isolation model?
@@ -0,0 +1,12 @@
1
+ ## What & why
2
+
3
+ <!-- What does this change and why? Link any related issue. -->
4
+
5
+ ## Checklist
6
+
7
+ - [ ] `ruff check src tests` passes
8
+ - [ ] `pytest` passes
9
+ - [ ] Updated `CHANGELOG.md`
10
+ - [ ] Preserves isolation/privacy invariants (no external reads; outbound-only
11
+ notifications; agent output still passes the secret backstop)
12
+ - [ ] Docs updated if behavior/config changed
@@ -0,0 +1,62 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ leak-gate:
10
+ # Generic OSS: fail if any org-specific identifier leaks in.
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+ - name: Org-leak gate
15
+ run: bash scripts/check_no_org_leak.sh
16
+
17
+ lint-test:
18
+ runs-on: ubuntu-latest
19
+ strategy:
20
+ matrix:
21
+ python-version: ["3.11", "3.12"]
22
+
23
+ services:
24
+ postgres:
25
+ image: postgres:16-alpine
26
+ env:
27
+ POSTGRES_USER: nexor_agora
28
+ POSTGRES_PASSWORD: nexor-agora
29
+ POSTGRES_DB: nexor_agora
30
+ ports:
31
+ - 5432:5432
32
+ options: >-
33
+ --health-cmd "pg_isready -U nexor_agora -d nexor_agora"
34
+ --health-interval 10s
35
+ --health-timeout 5s
36
+ --health-retries 5
37
+
38
+ env:
39
+ NEXOR_AGORA_DATABASE_URL: postgresql://nexor_agora:nexor-agora@localhost:5432/nexor_agora
40
+
41
+ steps:
42
+ - uses: actions/checkout@v4
43
+
44
+ - uses: actions/setup-python@v5
45
+ with:
46
+ python-version: ${{ matrix.python-version }}
47
+
48
+ - name: Install
49
+ run: pip install -e ".[dev]"
50
+
51
+ - name: Lint
52
+ run: ruff check src tests
53
+
54
+ - name: Test
55
+ run: pytest -q
56
+
57
+ docker-build:
58
+ runs-on: ubuntu-latest
59
+ steps:
60
+ - uses: actions/checkout@v4
61
+ - name: Build image
62
+ run: docker build -t nexor-agora:ci .
@@ -0,0 +1,47 @@
1
+ name: Release
2
+
3
+ # Publishes nexor-agora to PyPI via Trusted Publishing (OIDC) — no API tokens.
4
+ # PyPI mints short-lived credentials from the GitHub OIDC identity.
5
+ # Trigger by pushing a version tag, e.g. `git tag v0.1.0 && git push origin v0.1.0`.
6
+ #
7
+ # One-time PyPI setup (pending publisher, before the first release):
8
+ # PyPI → project nexor-agora → Publishing → add a GitHub publisher:
9
+ # owner=nexorhq · repo=nexor-agora · workflow=release.yml · environment=pypi
10
+
11
+ on:
12
+ push:
13
+ tags: ["v*"]
14
+ workflow_dispatch:
15
+
16
+ jobs:
17
+ build:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - name: Org-leak gate (block publish on any org identifier)
22
+ run: bash scripts/check_no_org_leak.sh
23
+ - uses: astral-sh/setup-uv@v5
24
+ with:
25
+ enable-cache: true
26
+ - name: Build sdist + wheel
27
+ run: uv build --out-dir dist
28
+ - uses: actions/upload-artifact@v4
29
+ with:
30
+ name: dist
31
+ path: dist/
32
+
33
+ publish:
34
+ needs: build
35
+ runs-on: ubuntu-latest
36
+ environment: pypi
37
+ permissions:
38
+ id-token: write
39
+ steps:
40
+ - uses: actions/download-artifact@v4
41
+ with:
42
+ name: dist
43
+ path: dist/
44
+ - name: Publish to PyPI
45
+ uses: pypa/gh-action-pypi-publish@release/v1
46
+ with:
47
+ skip-existing: true
@@ -0,0 +1,9 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .env
4
+ .venv/
5
+ *.egg-info/
6
+ dist/
7
+ build/
8
+ .pytest_cache/
9
+ .ruff_cache/
@@ -0,0 +1,68 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format is based on
4
+ [Keep a Changelog](https://keepachangelog.com/), and the project aims to follow
5
+ [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [Unreleased]
8
+
9
+ ### Changed — hub is now a pure, vendor-neutral coordination plane
10
+ - **Extracted the agent runner.** Removed `autoreply.py` and the `nexor-agora
11
+ agent` CLI subcommand. Driving an agent (auto-reply, task execution) couples to
12
+ a specific agent runtime, a license/API key, billing and personal risk
13
+ appetite — none of which belong in an OSS team hub. That logic now lives in an
14
+ **external runner** that connects over the public API (reference
15
+ implementation: `nexor/services/agora-runner`).
16
+ - The hub keeps everything an external runner needs: the `auto_reply` flag,
17
+ `chat_set_auto_reply`, `chat_wait`, `/tasks/mine`, escalation, and the
18
+ **server-side** secret backstop + audit trail. No agent-runtime dependency
19
+ remains. README/SETUP/.env reframed accordingly.
20
+
21
+ ### Plans & tasks (RFC-001)
22
+ - Conversations can optionally **follow a plan** (`conversations.plan_ref`,
23
+ nullable): free/exploratory by default, bindable to an existing repo plan, or
24
+ crystallized from the discussion. The hub never reads/writes repos.
25
+ - **Task coordination**: import a Spec-Kit `tasks.md` (or any markdown
26
+ checklist) deterministically (no LLM); per-step status, atomic self-claim
27
+ (Postgres row-lock), and lead assignment that **wakes the assignee via an
28
+ @mention**. Done by a non-lead lands in `review` for lead confirmation (guards
29
+ against stale "done" state). New `chat_bind_plan`, `chat_promote_plan`,
30
+ `chat_list_tasks`, `chat_my_tasks`, `chat_claim_task`, `chat_assign_task`,
31
+ `chat_task_status` MCP tools (+ REST under `/conversations/{id}/tasks`).
32
+ - **Decisions / variations** as a first-class artifact for discoveries that
33
+ change a plan — `chat_record_decision` / `chat_resolve_decision`. Resolution
34
+ records a downstream-propagation proposal; the hub never applies it.
35
+ - Design doc: `docs/rfc-001-plans-and-tasks.md`.
36
+
37
+ ### Security & usability (latest)
38
+ - API keys are now stored **hashed** (SHA-256); plaintext shown once at
39
+ registration, with `POST /me/rotate-key` to rotate. **Breaking** (pre-1.0):
40
+ existing plaintext keys are invalidated on upgrade.
41
+ - **Lead-only** management: roles, invites, membership and repos require a lead.
42
+ - **Server-side secret backstop** rejects messages that look like credentials
43
+ (`NEXOR_AGORA_BLOCK_SECRETS`), plus an **audit trail** of agent actions
44
+ (`GET /conversations/{id}/audit`).
45
+ - Web UI: Markdown/code-block rendering, @mention autocomplete, a profile panel
46
+ (display name, Telegram/Slack ids, key rotation), and "load earlier" pagination.
47
+ - Message history pagination via `before=`.
48
+
49
+ ### Added
50
+ - Shared conversations where humans and Claude Code agents are participants.
51
+ - Per-user API keys, conversations (1:1 and group channels), messages, inbox,
52
+ unread tracking, read receipts.
53
+ - `@mention` parsing with forced notifications: mentioned humans are pinged on
54
+ Slack (and Telegram for escalations); mentioned agents are woken.
55
+ - `chat_wait` blocking long-poll — the reliable way to wake a waiting agent
56
+ session (plus SSE for the live web UI).
57
+ - Optional `nexor-agora agent` runner: role-aware auto-reply (member vs **lead**),
58
+ with anti-loop safety (mention-gating, no unsolicited bot-to-bot, turn caps,
59
+ cooldown, repetition guard) and **per-conversation budget** enforcement.
60
+ - Roles (`lead`/`member`, multiple leads) and **working-repo** metadata.
61
+ - Invite links + `chat_join` so teammates (and their agents) join from a Slack link.
62
+ - Outbound Telegram (escalation DMs) and Slack (channel) notifications.
63
+ - Privacy guardrails: isolated MCP config, strict prompt clause, and an outgoing
64
+ secret backstop.
65
+ - Zero-build static web UI; single-file stdlib-only MCP server; Docker Compose
66
+ stack with a dedicated Postgres; `nexor-agora` CLI (`serve` / `agent` / `mcp`).
67
+
68
+ [Unreleased]: https://github.com/nexorhq/nexor-agora/commits/main
@@ -0,0 +1,16 @@
1
+ # Code of Conduct
2
+
3
+ This project adopts the [Contributor Covenant](https://www.contributor-covenant.org/),
4
+ version 2.1.
5
+
6
+ In short: be respectful, welcoming, and constructive. Harassment and
7
+ discrimination of any kind are not tolerated. Maintainers may remove,
8
+ edit, or reject contributions and comments that violate this code, and may
9
+ ban contributors for inappropriate behavior.
10
+
11
+ To report unacceptable behavior, contact the maintainer privately (see
12
+ [SECURITY.md](./SECURITY.md) for contact options). Reports will be handled
13
+ confidentially.
14
+
15
+ The full text is available at
16
+ https://www.contributor-covenant.org/version/2/1/code_of_conduct/.
@@ -0,0 +1,52 @@
1
+ # Contributing to nexor-agora
2
+
3
+ Thanks for your interest! nexor-agora is a small, self-hostable project and
4
+ contributions are very welcome.
5
+
6
+ ## Development setup
7
+
8
+ ```bash
9
+ git clone <repo> && cd nexor-agora
10
+ python -m venv .venv && source .venv/bin/activate
11
+ pip install -e ".[dev]"
12
+
13
+ # Lint + tests
14
+ ruff check src tests
15
+ pytest
16
+ ```
17
+
18
+ The hub needs a Postgres to run end to end. The quickest way:
19
+
20
+ ```bash
21
+ docker compose up -d db # just the database
22
+ export NEXOR_AGORA_DATABASE_URL=postgresql://nexor_agora:nexor-agora@localhost:5432/nexor_agora
23
+ nexor-agora serve
24
+ ```
25
+
26
+ ## Project layout
27
+
28
+ ```
29
+ src/nexor-agora/
30
+ app.py FastAPI app (routes, SSE, static UI)
31
+ store.py all SQL / data access
32
+ db.py asyncpg pool + idempotent schema
33
+ models.py pydantic request/response models
34
+ notify.py outbound Telegram/Slack
35
+ autoreply.py the `nexor-agora agent` runner (role-aware, budgeted, privacy-guarded)
36
+ mcp_server.py the `nexor-agora mcp` stdio server (stdlib-only)
37
+ cli.py `nexor-agora serve|agent|mcp`
38
+ static/index.html zero-build web UI
39
+ tests/ unit tests (mentions, privacy) + optional integration
40
+ ```
41
+
42
+ ## Guidelines
43
+
44
+ - Keep the **isolation/privacy** invariants: the hub must never read from external
45
+ systems; notifications are outbound only; agent output passes the secret backstop.
46
+ - Run `ruff check` (config in `pyproject.toml`) and `pytest` before opening a PR.
47
+ - Keep `mcp_server.py` **standard-library only** so it stays copy-paste portable.
48
+ - Small, focused PRs with a clear description. Add a `CHANGELOG.md` entry.
49
+
50
+ ## Reporting bugs / ideas
51
+
52
+ Open an issue using the templates. For security issues, see [SECURITY.md](./SECURITY.md).
@@ -0,0 +1,20 @@
1
+ # nexor-agora hub — FastAPI + static UI. Self-contained (pip, no workspace).
2
+ FROM python:3.12-slim
3
+
4
+ WORKDIR /app
5
+
6
+ COPY pyproject.toml README.md ./
7
+ COPY src/ ./src/
8
+
9
+ RUN pip install --no-cache-dir .
10
+
11
+ ENV NEXOR_AGORA_HOST=0.0.0.0 \
12
+ NEXOR_AGORA_PORT=8400 \
13
+ NEXOR_AGORA_LOG_LEVEL=INFO
14
+
15
+ EXPOSE 8400
16
+
17
+ HEALTHCHECK --interval=15s --timeout=5s --retries=5 --start-period=15s \
18
+ CMD python -c "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://localhost:8400/api/v1/health').status==200 else 1)" || exit 1
19
+
20
+ CMD ["python", "-m", "nexor_agora", "serve"]
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Giovanni Consiglio and nexor-agora contributors
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.
@@ -0,0 +1,40 @@
1
+ .PHONY: help install dev lint test serve agent db up down fmt
2
+
3
+ help:
4
+ @echo "install Install the package"
5
+ @echo "dev Install with dev extras (ruff, pytest)"
6
+ @echo "lint Run ruff"
7
+ @echo "test Run pytest"
8
+ @echo "db Start only the Postgres container"
9
+ @echo "serve Run the hub locally"
10
+ @echo "up/down docker compose up -d / down"
11
+
12
+ install:
13
+ pip install .
14
+
15
+ dev:
16
+ pip install -e ".[dev]"
17
+
18
+ lint:
19
+ ruff check src tests
20
+
21
+ fmt:
22
+ ruff check --fix src tests
23
+
24
+ test:
25
+ pytest
26
+
27
+ db:
28
+ docker compose up -d db
29
+
30
+ serve:
31
+ nexor-agora serve
32
+
33
+ agent:
34
+ nexor-agora agent
35
+
36
+ up:
37
+ docker compose up -d
38
+
39
+ down:
40
+ docker compose down