MISSILYA GROUP Core SDK — unified, vault-backed infrastructure for AI, payments, notifications, auth, and monitoring.
Project description
missilya-sdk
MISSILYA GROUP Core SDK — one versioned, vault-backed Python package that
replaces the copy-pasted emergentintegrations code spread across the MISSILYA
ecosystem. It gives every application a single, provider-agnostic API for AI,
payments, notifications, auth, secrets, and monitoring, with credentials sourced
from MISSILYA VAULT and no vendor lock-in.
- Package:
missilya-sdk· Import namespace:missilya_sdk - Runtime: staging & production (routes to real providers using vault keys)
- Python: 3.11 – 3.13
- Sandbox twin:
missilya-sdk-sandbox— API-identical, deterministic, offline (use in development & CI)
Status: private, under review. After approval the package is published to the MISSILYA private pip registry so any project can
pip install missilya-sdk.
Table of contents
- Why this exists
- Install
- Quickstart
- Core concepts
- Configuration & the vault
- Module reference
- The Adapter Engine & failover
- Multi-tenant usage
- Error handling
- Observability
- Security model
- Governance & CI
- Migration from emergentintegrations
- Sandbox parity & versioning
- Local development
- Project layout
1. Why this exists
emergentintegrations was vendored (copy-pasted) into ~35 repositories. Each copy
drifted: no versioning, no tests, no CI, hardcoded API keys. This SDK fixes that:
Before (emergentintegrations) |
After (missilya_sdk) |
|---|---|
| Copy in every repo, silently diverging | One versioned package, one source of truth |
| OpenAI-only, tightly coupled | 100+ models via the Adapter Engine, swappable |
Hardcoded keys / .env |
VAULT-first, fail-closed in production |
| No tests, no CI | Strict typing, tests, parity check, CI gates |
| Direct vendor imports everywhere | Apps import only missilya_sdk (CI-enforced) |
2. Install
Install only the modules a service needs (optional extras keep the dependency surface small):
pip install "missilya-sdk[ai]" # LLM, images, TTS, STT, translation
pip install "missilya-sdk[payments]" # Stripe
pip install "missilya-sdk[notifications]" # Resend (email), Twilio (SMS/WhatsApp)
pip install "missilya-sdk[auth]" # Google sign-in (RS256 verification)
pip install "missilya-sdk[monitoring]" # Sentry
pip install "missilya-sdk[all]" # everything
| Extra | Installs |
|---|---|
[ai] |
litellm, openai, elevenlabs, deepl |
[payments] |
stripe |
[notifications] |
resend, twilio |
[auth] |
cryptography (Google ID-token RS256 verification) |
[monitoring] |
sentry-sdk |
[all] |
all of the above |
[dev] |
pytest, ruff, mypy, build, twine, … |
Installing into a MISSILYA repo
Until the package is published to the private registry, depend on it directly from GitHub (pin a tag or commit for reproducibility):
pip install "missilya-sdk[all] @ git+https://github.com/MISSILYA-GROUP/MISSILYA-CORE-SDK.git@v0.2.0"
For development/CI, use the sandbox twin (offline, deterministic, no provider keys) and swap to core by environment — not by import:
pip install "missilya-sdk-sandbox @ git+https://github.com/MISSILYA-GROUP/MISSILYA-SANDBOX-SDK.git@v0.2.0"
Production readiness
Every module is type-checked (mypy --strict) and has 100% test coverage
(enforced in CI). Unit tests exercise provider boundaries with mocks, so
before relying on a provider-backed capability in production, run the live smoke
suite once in an environment that has the real credentials (or vault access):
MISSILYA_RUN_INTEGRATION=1 pytest tests/integration -m integration --no-cov -v
Each smoke test self-skips unless its credentials are present, and makes the smallest real call that proves the round-trip (vault read, chat completion, Stripe test session, email/SMS/WhatsApp send, Google ID-token verify).
One-click in CI: the Live Integration Smoke GitHub Actions workflow
(.github/workflows/integration.yml, manual Run workflow) runs the same suite
using repository secrets — no local setup. Configure under
Settings → Secrets and variables → Actions (each capability self-skips if its
secret is absent, so you can validate incrementally):
| Secret | For |
|---|---|
MISSILYA_VAULT_URL, MISSILYA_VAULT_CLIENT_ID/SECRET, MISSILYA_VAULT_PROJECT_ID |
vault read (requires a reachable vault.missilya.com) |
OPENAI_API_KEY |
chat completion |
STRIPE_TEST_SECRET_KEY |
checkout session (TEST key) |
RESEND_API_KEY + var MISSILYA_SMOKE_EMAIL_TO |
|
TWILIO_ACCOUNT_SID/AUTH_TOKEN + vars TWILIO_SMS_FROM, MISSILYA_SMOKE_SMS_TO |
SMS |
WHATSAPP_ACCESS_TOKEN + vars WHATSAPP_PHONE_NUMBER_ID, MISSILYA_SMOKE_WHATSAPP_TO |
|
GOOGLE_OAUTH_CLIENT_ID, GOOGLE_TEST_ID_TOKEN |
Google sign-in |
ai.generate_videois a stub. No cross-provider video API is wired into core yet; it raisesProviderErrorby design. The sandbox returns a fixture so app code can integrate against the shape. Do not depend on live video until a provider adapter is added.
For development and CI, install the offline twin instead — same import, no real
calls: pip install missilya-sdk-sandbox.
3. Quickstart
from missilya_sdk.ai.chat import LlmChat, SystemMessage, UserMessage
chat = LlmChat(model="gpt-4o") # key resolved from VAULT
chat.add_message(SystemMessage("You are a MISSILYA assistant."))
chat.add_message(UserMessage("Explain our subscription tiers."))
print(chat.chat()) # -> str (legacy-compatible)
No API keys in code. No import openai. The SDK resolves the right credential from
the vault, routes through the Adapter Engine, and returns a normalized result.
4. Core concepts
| Concept | What it is |
|---|---|
| Unified API | missilya_sdk.<domain>.<capability> — apps never touch a vendor SDK. |
| Adapter Engine | Internal layer that resolves credentials, picks a provider, normalizes responses, and fails over. |
| VAULT-first config | Credentials come from MISSILYA VAULT; production fails closed if a secret is missing. |
| TenantContext | Scopes every call (vault path, billing, audit) to one tenant. |
| Typed errors | Every failure is a missilya_sdk.exceptions.* subclass of MissilyaError. |
| Sandbox parity | The sandbox package mirrors this public API exactly, verified in CI. |
5. Configuration & the vault
Credentials resolve in this order (config.get_config):
- MISSILYA VAULT (Infisical) — required for staging/production
- CI/vault-injected environment variable (deployment bridge)
- Local environment variable (development only)
- Non-secret default (if provided)
- Fail closed →
ConfigurationError
In production, a secret resolved from a plain environment variable is
rejected unless MISSILYA_ALLOW_ENV_SECRETS=1 (an approved CI/vault bridge).
Runtime environment variables
| Variable | Purpose |
|---|---|
MISSILYA_VAULT_URL |
Vault base URL. Defaults to https://vault.missilya.com. |
MISSILYA_VAULT_CLIENT_ID / ..._CLIENT_SECRET |
Machine-identity Universal Auth (recommended). |
MISSILYA_VAULT_TOKEN |
Static service/access token (alternative to Universal Auth). |
MISSILYA_VAULT_PROJECT_ID |
Infisical project for app secrets. |
MISSILYA_VAULT_SHARED_PROJECT_ID |
Project holding shared provider keys. |
MISSILYA_ENV |
development / staging / production. |
MISSILYA_ALLOW_ENV_SECRETS |
Set 1 only for an approved CI/vault bridge in production. |
See .env.example for the full list of secret names
(OPENAI_API_KEY, STRIPE_SECRET_KEY, RESEND_API_KEY, JWT_SECRET,
SENTRY_DSN, …).
How the vault call works
VaultClient speaks the Infisical REST API:
- Universal Auth login:
POST /api/v1/auth/universal-auth/login→ short-lived access token (cached in memory until just before expiry). - Read secret:
GET /api/v4/secrets/{name}?projectId=&environment=&secretPath=/→{ "secret": { "secretValue": "..." } }.
Provider keys (e.g. OPENAI_API_KEY) fall back to the shared project;
app-specific secrets come from the app project. Values are cached briefly,
never logged, and the client retries transient failures with backoff.
6. Module reference
missilya_sdk.ai.chat — LLM chat
from missilya_sdk.ai.chat import LlmChat, SystemMessage, UserMessage, AssistantMessage
chat = LlmChat(model="gpt-4o", fallbacks=["claude-sonnet-4-20250514"])
chat.add_message(SystemMessage("Be concise."))
chat.add_message(UserMessage("Summarize Q2 in one sentence."))
text = chat.chat() # -> str (emergentintegrations-compatible)
resp = chat.complete() # -> ChatResponse(content, model, provider, usage, raw)
print(resp.usage.total_tokens)
# Async + streaming
text = await chat.achat()
async for delta in chat.astream():
print(delta, end="")
Model strings follow the LiteLLM convention: "gpt-4o", "claude-sonnet-4-...",
"gemini/gemini-2.5-pro", "mistral/...", "deepseek/...".
missilya_sdk.ai.images — image generation
from missilya_sdk.ai.images import generate_image
img = generate_image("a neon skyline at dusk", model="dall-e-3", size="1024x1024")
print(img.url)
missilya_sdk.ai.tts / .stt — speech
from missilya_sdk.ai.tts import text_to_speech
from missilya_sdk.ai.stt import speech_to_text
audio = text_to_speech("Hello from MISSILYA", voice_id="JBFqnCBsd6RMkjVDRZzb")
open("hello.mp3", "wb").write(audio.audio)
transcript = speech_to_text(open("hello.mp3", "rb").read())
print(transcript.text)
missilya_sdk.ai.translation — translation
from missilya_sdk.ai.translation import translate
print(translate("Bonjour le monde", target_lang="EN-US").text)
missilya_sdk.payments.stripe — payments
from missilya_sdk.payments.stripe import StripeCheckout
from missilya_sdk.payments.checkout import CheckoutSessionRequest
checkout = StripeCheckout()
session = checkout.create_session(CheckoutSessionRequest(
line_items=[{"price": "price_123", "quantity": 1}],
success_url="https://app.missilya.com/success",
cancel_url="https://app.missilya.com/cancel",
customer_email="client@example.com",
))
print(session.url)
# Webhook (signature verified against vault STRIPE_WEBHOOK_SECRET)
event = checkout.handle_webhook(request_body, signature_header)
missilya_sdk.notifications — email / SMS / WhatsApp
from missilya_sdk.notifications.email import send_email
from missilya_sdk.notifications.sms import send_sms
from missilya_sdk.notifications.whatsapp import send_whatsapp
send_email(to="user@example.com", subject="Welcome", html="<h1>Hi</h1>")
send_sms(to="+10000000000", body="Your code is 123456")
send_whatsapp(to="+10000000000", body="Your order shipped")
missilya_sdk.whatsapp — two-way WhatsApp (Meta Cloud API or Twilio)
from missilya_sdk.whatsapp import WhatsAppClient, parse_inbound, verify_signature
wa = WhatsAppClient() # provider from WHATSAPP_PROVIDER (default "meta")
wa.send_text("+10000000000", "Your order shipped")
wa.send_template("+10000000000", "order_update", language="en_US")
wa.send_media("+10000000000", "https://cdn.example.com/receipt.pdf", kind="document")
# Inbound webhook (framework-agnostic):
verify_signature(raw_body, request.headers["X-Hub-Signature-256"]) # fail-closed
for msg in parse_inbound(raw_body):
print(msg.from_number, msg.text)
wa.mark_read(msg.message_id)
The Meta Cloud API is the default backend; set WHATSAPP_PROVIDER=twilio to use
Twilio instead. Credentials (WHATSAPP_ACCESS_TOKEN, WHATSAPP_PHONE_NUMBER_ID,
WHATSAPP_APP_SECRET, WHATSAPP_VERIFY_TOKEN) come from MISSILYA VAULT.
missilya_sdk.auth.jwt — JWT helpers
from missilya_sdk.auth.jwt import create_token, verify_token
token = create_token({"sub": "user-1"}, expires_in=3600) # signed with vault JWT_SECRET
claims = verify_token(token) # raises AuthenticationError if invalid
missilya_sdk.auth.google — Google Sign-In (OIDC → Missilya JWT)
from missilya_sdk.auth import sign_in_with_google, verify_google_token
# Verify a Google ID token from the client (validates signature, issuer, aud, exp):
identity = verify_google_token(google_id_token) # -> GoogleIdentity(sub, email, ...)
# Or verify AND mint a first-party Missilya session token in one step:
session = sign_in_with_google(google_id_token)
session.token # a Missilya JWT (verify with auth.jwt.verify_token)
session.identity # the verified GoogleIdentity
RS256 verification needs the [auth] extra: pip install "missilya-sdk[auth]".
The audience defaults to the vault-resolved GOOGLE_OAUTH_CLIENT_ID.
missilya_sdk.vault.client — direct vault access
from missilya_sdk.vault.client import VaultClient
client = VaultClient(url="https://vault.missilya.com",
client_id="...", client_secret="...", project_id="...")
value = client.get_secret("SOME_APP_SECRET", environment="production")
Application code rarely calls
VaultClientdirectly for provider keys — the capability modules resolve their own credentials internally.
Public import surface (v0.1.0)
from missilya_sdk import MissilyaSDK, TenantContext, get_config
from missilya_sdk.ai.chat import LlmChat, UserMessage, SystemMessage, AssistantMessage, ChatResponse, ChatUsage
from missilya_sdk.ai.images import generate_image, ImageResult
from missilya_sdk.ai.tts import text_to_speech, SpeechResult
from missilya_sdk.ai.stt import speech_to_text, TranscriptResult
from missilya_sdk.ai.translation import translate, TranslationResult
from missilya_sdk.ai.video import generate_video, VideoJob
from missilya_sdk.payments.stripe import StripeCheckout
from missilya_sdk.payments.checkout import CheckoutSessionRequest, CheckoutSession, WebhookEvent
from missilya_sdk.notifications import send_email, send_sms, send_whatsapp, DeliveryResult
from missilya_sdk.auth.jwt import create_token, verify_token, decode_token
from missilya_sdk.monitoring import get_logger, new_correlation_id, track_event, init_sentry, capture_exception, capture_message
from missilya_sdk.exceptions import MissilyaError, ConfigurationError, ProviderError, RateLimitError, VaultError
7. The Adapter Engine & failover
Every LLM call flows through one engine so the application never targets a vendor:
App → LlmChat → Adapter Engine
├─ resolve credential from VAULT (per provider)
├─ dispatch via LiteLLM to the chosen model
├─ on failure, fail over to the next model in `fallbacks`
└─ normalize response + usage; emit redacted telemetry
chat = LlmChat(
model="gpt-4o",
fallbacks=["claude-sonnet-4-20250514", "gemini/gemini-2.5-pro"],
)
If OpenAI errors, the engine automatically retries with Anthropic, then Gemini —
no application change. Errors are normalized to typed exceptions
(RateLimitError, ProviderTimeoutError, ProviderAuthError, ProviderError).
8. Multi-tenant usage
from missilya_sdk import TenantContext
from missilya_sdk.ai.chat import LlmChat, UserMessage
ctx = TenantContext(tenant_id="civytax", env="production")
chat = LlmChat(model="gpt-4o", context=ctx)
chat.add_message(UserMessage("Calculate taxes for ..."))
answer = chat.chat() # key resolved from the civytax scope; usage tagged to civytax
The context drives the vault project/path, tags telemetry for per-tenant billing, and adds traceability headers. A convenience facade is also available:
from missilya_sdk import MissilyaSDK
sdk = MissilyaSDK(tenant_id="civytax", environment="production")
chat = sdk.chat(model="gpt-4o")
9. Error handling
All failures are subclasses of MissilyaError:
MissilyaError
├── ConfigurationError
├── ProviderError
│ ├── RateLimitError
│ ├── ProviderTimeoutError
│ └── ProviderAuthError
├── AuthenticationError
├── VaultError
│ ├── VaultConnectionError
│ └── VaultSecretNotFound
└── ValidationError
from missilya_sdk.exceptions import MissilyaError, RateLimitError
try:
answer = chat.chat()
except RateLimitError:
... # back off / queue
except MissilyaError as exc:
log.error("sdk_error", error=str(exc))
10. Observability
from missilya_sdk.monitoring import get_logger, new_correlation_id, init_sentry, capture_exception
log = get_logger(__name__) # structured, secret-redacting logger
init_sentry() # DSN from vault SENTRY_DSN; no-op if absent
def handle(req):
new_correlation_id() # correlate every log line for this request
try:
...
except Exception as exc:
capture_exception(exc) # report to Sentry if configured
raise
Logs emit structured JSON and automatically redact API keys, bearer tokens,
sk-…/sk_live_…/whsec_… patterns, card data, and other sensitive fields.
track_event(...) / track_latency(...) record usage and latency.
11. Security model
- No plaintext secrets anywhere in code or
.env(production fails closed). - Secrets never logged — redaction is applied before anything is emitted.
- Least privilege — runtime uses a read-only machine identity scoped to one project/environment.
- Production guards —
StripeCheckoutrequires a live key in production; the config layer refuses plain-env secrets in production by default. - Provenance — releases record SHA-256 hashes of build artifacts.
12. Governance & CI
- Forbidden-import gate:
tools/check_forbidden_imports.pyfails CI if app code importsopenai/stripe/twilio/anthropic/litellm/resend/… directly. - Quality gate:
ruff(lint) +mypy --strict(types) +pytest(tests) on Python 3.11/3.12/3.13. - Secret scan: gitleaks on every push/PR.
- Release: tag → build sdist/wheel →
twine check→ SHA-256 ledger → publish to the private registry (manual production approval gate). - Container:
Dockerfile+ GHCR publish workflow. - Zone: classified
A(foundation) inrepo.classification.yml.
13. Migration from emergentintegrations
Mostly a find-and-replace on imports; see docs/migration-guide.md.
| Legacy | MISSILYA SDK |
|---|---|
from emergentintegrations.llm.chat import LlmChat, UserMessage |
from missilya_sdk.ai.chat import LlmChat, UserMessage |
from emergentintegrations.payments.stripe.checkout import StripeCheckout |
from missilya_sdk.payments.stripe import StripeCheckout |
resend.Emails.send(...) |
from missilya_sdk.notifications.email import send_email |
The LlmChat / StripeCheckout APIs are preserved, so most migrations need no
business-logic changes — just the import path and removing hardcoded keys.
14. Sandbox parity & versioning
- The sandbox package exposes an identical public API (same names, signatures,
return shapes). This is verified statically by
repos/sdk-tools/check_sdk_parity.pyand as a test. - Versions are kept in lock-step (
src/missilya_sdk/_version.py); a feature cannot land in core without matching sandbox behavior. - The package follows SemVer. Current version:
0.1.0.
15. Local development
python -m venv .venv
./.venv/Scripts/python -m pip install -e ".[all,dev]" # Windows
# source .venv/bin/activate && pip install -e ".[all,dev]" # macOS/Linux
ruff check src tests tools
mypy src/missilya_sdk
pytest -q
python -m build && twine check dist/*
16. Project layout
src/missilya_sdk/
├── __init__.py # public top-level exports
├── config.py # VAULT-first config resolution
├── context.py # TenantContext, MissilyaSDK facade
├── exceptions.py # typed error hierarchy
├── ai/ # chat (+_engine adapter), images, tts, stt, translation, video
├── payments/ # stripe, checkout models
├── notifications/ # email, sms, whatsapp
├── auth/ # jwt
├── vault/ # Infisical client
└── monitoring/ # logging, analytics, sentry
tests/ # unit + smoke + parity tests
tools/check_forbidden_imports.py
docs/ # getting-started, migration-guide
.github/workflows/ # test, publish, release, docker-publish
Dockerfile · repo.classification.yml · .env.example
License
Proprietary — © 2026 MISSILYA GROUP. See LICENSE. Private to MISSILYA GROUP; redistribution requires written authorization from Yvon Kamach (CEO).
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file missilya_sdk-0.2.0.tar.gz.
File metadata
- Download URL: missilya_sdk-0.2.0.tar.gz
- Upload date:
- Size: 61.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3a91122270d6dd2f2677c0926760d50f05c701790450109a4c406f176f5a9d4c
|
|
| MD5 |
c4ad304cd8227fa260aa9b0d54f97a1c
|
|
| BLAKE2b-256 |
13c61c8317b9486efac69d74e78f9f0cf753b96803976c8269579f4dbee1b0e1
|
Provenance
The following attestation bundles were made for missilya_sdk-0.2.0.tar.gz:
Publisher:
publish.yml on MISSILYA-GROUP/MISSILYA-CORE-SDK
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
missilya_sdk-0.2.0.tar.gz -
Subject digest:
3a91122270d6dd2f2677c0926760d50f05c701790450109a4c406f176f5a9d4c - Sigstore transparency entry: 2168757004
- Sigstore integration time:
-
Permalink:
MISSILYA-GROUP/MISSILYA-CORE-SDK@2f911ec0b3229eaab123077654b367e153381e2c -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/MISSILYA-GROUP
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2f911ec0b3229eaab123077654b367e153381e2c -
Trigger Event:
push
-
Statement type:
File details
Details for the file missilya_sdk-0.2.0-py3-none-any.whl.
File metadata
- Download URL: missilya_sdk-0.2.0-py3-none-any.whl
- Upload date:
- Size: 58.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
db5be8195642c17732da3dc5c9cc225e062fb0c8c8919030c7e6a6f2540edd4d
|
|
| MD5 |
c20aae9dfcc786074204cc041128b5c5
|
|
| BLAKE2b-256 |
fe24ab56dc6b95e3ea946084031a4eaabc1540fe4aeedb36f9ed494da90f54de
|
Provenance
The following attestation bundles were made for missilya_sdk-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on MISSILYA-GROUP/MISSILYA-CORE-SDK
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
missilya_sdk-0.2.0-py3-none-any.whl -
Subject digest:
db5be8195642c17732da3dc5c9cc225e062fb0c8c8919030c7e6a6f2540edd4d - Sigstore transparency entry: 2168757017
- Sigstore integration time:
-
Permalink:
MISSILYA-GROUP/MISSILYA-CORE-SDK@2f911ec0b3229eaab123077654b367e153381e2c -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/MISSILYA-GROUP
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2f911ec0b3229eaab123077654b367e153381e2c -
Trigger Event:
push
-
Statement type: