Hórus is the internal codename for this service: the analyst copilot that watches Jira tickets and leaves a private draft before the human SA replies.
Why Hórus? In Egyptian myth the Eye of Horus (Wedjat) stood for protection, healing, and seeing the whole picture — exactly what we want from a copilot that reads the thread, searches KB + docs, and whispers an internal note: "here's what I saw; you decide what goes to the customer." It does not post public comments. The eye watches; the SA speaks.
FastAPI service that receives Jira webhooks, runs a multi-agent Agno pipeline (Planner → parallel Docs/GitHub researchers → Response), and writes a private draft back to Jira for Minders Solutions Architects.
Domains: Braze, Amplitude, AirBridge, martech/growth guidance — never a customer-visible reply.
- Python 3.11+
- GCP credentials — BigQuery + embeddings for KB search (
GOOGLE_APPLICATION_CREDENTIALS) - API keys (as needed):
ANTHROPIC_API_KEY— Agno agents (AI_PROVIDER=agno)OPENAI_API_KEY— embeddings for semantic KB searchTAVILY_API_KEY— optional web search fallbackGITHUB_TOKEN— optional SDK deep researchJIRA_API_TOKEN+JIRA_WEBHOOK_SECRET— draft handoff + webhook auth
# 1. Clone and enter the repo
cd sa-copilot-api
# 2. Virtual environment
python3 -m venv .venv
source .venv/bin/activate
# 3. Install dependencies
pip install -r requirements.txt
pip install -r requirements-dev.txt # pytest, ruff
# 4. Environment
cp .env.example .env
# Edit .env — add API keys, GCP creds, Jira tokens (never commit .env)
# 5. Run the API
fastapi dev
# or: uvicorn main:app --reloadHealth check: GET http://127.0.0.1:8000/health
Set ENVIRONMENT in .env (local) or scripts/deploy.env.yaml (Cloud Run).
development (alias dev) |
production / staging |
|
|---|---|---|
Structured [agno] INFO logs |
yes | yes (grep '[agno]') |
Full trace files tmp/agno_traces/*.txt |
yes | no |
Eval CSV tmp/eval_results.csv |
yes | yes (ephemeral on Cloud Run) |
tmp/ persistence |
local disk | ephemeral per instance |
Implementation: app/config.py (settings.is_development) gates export_agno_trace() in
workflow_pipeline.py. Eval (append_to_csv) is not gated.
Cloud Run deploy sets ENVIRONMENT: production via scripts/deploy.env.yaml.
Golden cases live in app/evaluation/cases.py — add new cases there only.
# Layer 1 — retrieval recall@k (needs GCP + OpenAI)
python -m app.evaluation.retrieval --k 5 --csv # → tmp/eval_retrieval.csv
# Layer 2 — full agent response benchmark (needs AI_PROVIDER=agno + Anthropic)
pytest tests/test_ai_response.py -v -s -m ai_response # → tmp/eval_benchmark_report.csvLive webhooks also append to tmp/eval_results.csv in the background (all environments).
See app/evaluation/README.md and docs/EVALUATION_METHODOLOGY.md.
# 1. Sync secrets from .env → GCP Secret Manager (run when keys change)
./scripts/update_secrets.sh
# 2. Build image and deploy to Cloud Run
./scripts/deploy.shupdate_secrets.sh reads repo-root .env and creates/updates Secret Manager entries
(anthropic-api-key, openai-api-key, jira-*, tavily-api-key, github-token,
context7-api-key). Empty values are skipped. Override with ENV_FILE or PROJECT if needed.
deploy.sh builds the Docker image, deploys to Cloud Run with env vars from
scripts/deploy.env.yaml, and mounts those secrets via --set-secrets. See
scripts/gcp_config.sh for project/region.
main.py # FastAPI app + lifespan
app/
├── config.py # Settings (ENVIRONMENT, AI, MCP, Jira flags)
├── auth.py # Jira webhook HMAC verification (optional on route)
├── sanitization/ # prepare_ai_context, thread digest, image refs
├── guardrail.py # injection scan + datamark after sanitize
├── routers/jira.py # Webhook routes
├── use_cases/jira/ # One handler per Jira event
├── services/
│ ├── ai/agno/ # AgnoService, workflow_pipeline, prompts, io_log
│ │ └── mcp_plugins/ # kb_search, docs MCP, GitHub, Tavily, BQ, Notion*
│ └── jira/draft.py # Issue property / internal comment handoff
├── evaluation/ # Golden set, retrieval + response eval
├── models/ # AIContext, RetrievalBundle, Jira webhook DTOs
jobs/ # Cloud Function poller (webhook fallback)
knoledge_base/ # Config-driven KB pipeline → BigQuery
tests/ # Unit + benchmark tests
docs/ # Living specs, NEXT_PHASES, architecture audits
scripts/deploy.sh # Cloud Run deploy
* Notion MCP registered, off by default (NOTION_MCP_ENABLED).
See docs/NEXT_PHASES.md for deferred work (OCR, richer thread context, etc.). See jobs/README.md for the poller.
- New golden case — add
EvalCasetoapp/evaluation/cases.py, run both eval layers. - New MCP tool — file in
app/services/ai/agno/mcp_plugins/, register inregistry.py, add env flag toapp/config.py+.env.example. - New Jira event — use case in
app/use_cases/jira/, wire inapp/controllers/jira.py. - Prompt changes —
app/services/ai/agno/prompts.py(planner/response instructions). - New KB source — YAML in
knoledge_base/config/sources/(seedocs/KNOWLEDGE_PLANE.md).
Before opening a PR:
ruff check app main.py tests knoledge_base
pytest tests/ -v -m "not ai_response" # fast unit tests| Doc | Purpose |
|---|---|
| docs/SPECS.md | Living MVP specification |
| docs/AGENT_ARCHITECTURE.md | Agent pipeline, tools, logging |
| docs/KNOWLEDGE_PLANE.md | Config-driven KB standard |
| docs/KNOLEDGE_BASE.md | KB pipeline architecture |
| docs/EVALUATION_METHODOLOGY.md | Benchmark methodology |
| docs/JIRA_WEBHOOK_SETUP.md | Webhook signature setup |
| docs/superpowers/audits/ | Architecture snapshots |
Architecture ground truth is maintained via .cursor/skills/map-sa-copilot-architecture/SKILL.md.
