Event-driven business operations platform with integrated market intelligence and autonomous agent execution.
Skyrict is an open-source, AI-native platform that merges business operations (ERP) with real-time market intelligence into a single system. Traditional ERP treats your company as an isolated entity processing internal transactions. Skyrict treats your company as a node in a live global market — ingesting external signals, correlating them with internal operations, and letting AI agents act on the synthesis.
skyrict/
├── apps/ # Deployable frontend clients
│ ├── web/ # Next.js 15 / React 19 / TypeScript
│ ├── mobile/ # Mobile app scaffold
│ └── desktop/ # Desktop app scaffold
│
├── packages/ # Shared TypeScript packages
│ ├── api-client/ # Generated from OpenAPI schemas
│ ├── types/ # Shared TS types/interfaces
│ ├── ui/ # Shared React components
│ └── auth/ # Token storage, refresh logic
│
├── services/ # Deployable Python microservices
│ ├── identity/ # AuthN, AuthZ, MFA, Sessions, Audit
│ └── _template/ # Scaffold copied for every new service, keeps structure consistent
│
├── libs/ # Shared Python packages
│ ├── skyrict-common/ # Exceptions, logging, pagination, schemas
│ ├── skyrict-events/ # Kafka event schemas, producer/consumer base classes
│ └── skyrict-testing/ # Test fixtures, factories, JWT key generation
│
├── infra/ # Infrastructure as Code
│ ├── docker/ # Docker Compose for local dev
│ ├── k8s/ # Kubernetes manifests (base + overlays)
│ └── terraform/ # Cloud infrastructure
│
├── docs/
│ ├── architecture/adr/ # Architecture Decision Records
│ └── handbooks/ # Product & engineering handbooks
│
├── .github/ # GitHub governance & CI
│ ├── workflows/ # CI/CD workflows
│ ├── CODEOWNERS # Team-based review routing
│ └── dependabot.yml # Automated dependency updates
│
├── pyproject.toml # uv workspace root
├── package.json # pnpm workspace root
├── turbo.json # Frontend task pipeline
├── Makefile # Single entrypoint for all dev commands
└── ...
services/identity/src/identity/
├── api/ # FastAPI routes, dependency injection
├── core/ # Config, security, middleware, tenant context
├── domain/ # Pure Python entities and value objects
├── services/ # Application/use-case layer (business logic)
├── repositories/ # DB access only (no business logic)
├── models/ # SQLAlchemy ORM models
├── schemas/ # Pydantic request/response DTOs
├── events/ # Kafka event producers/consumers
└── db/ # Async engine, session factory, RLS
Why this layering: api → services → repositories → models. Business logic never touches the DB directly. JWT verification happens in exactly one place (core/security.py). Tenant context flows through a ContextVar, not function parameters.
| Layer | Choice |
|---|---|
| Python package manager | uv (workspaces, single lockfile) |
| Language | Python 3.12+ / TypeScript 5.7+ |
| Web framework | FastAPI (async, type-safe, OpenAPI) |
| ORM | SQLAlchemy 2.0 (async) + Alembic |
| Frontend | Next.js 15 / React 19 / shadcn/ui |
| Frontend tooling | pnpm + Turborepo |
| OLTP | PostgreSQL 16 + Row-Level Security |
| Cache | Redis 7 |
| Event bus | Kafka 3.x (KRaft mode) — deferred until 3+ services need async events |
| CI/CD | GitHub Actions (path-filtered) |
| Containers | Docker |
- Python 3.12+
- Node.js 20+
- Docker & Docker Compose v2
- uv (
curl -LsSf https://astral.sh/uv/install.sh | sh) - pnpm (
npm install -g pnpm)
git clone https://github.com/nkswalih/skyrict.git
cd skyrict
# 1. Install all dependencies
make setup
# 2. Configure the local environment
cp services/identity/.env.example services/identity/.env
uv run python -m skyrict_testing.generate_keys # JWT RS256 keys -> .dev/keys/ (gitignored)
# 3. Start dev servers (infra + identity service)
make dev
# 4. In another terminal, start the frontend
make dev-web- API docs:
http://localhost:8000/docs - Frontend:
http://localhost:3000
The identity service is multi-tenant: in production each tenant reaches it via
its own subdomain (https://acme.skyrict.com/...), and the ingress injects an
X-Tenant-Slug header before forwarding. The dev stack mirrors that contract
so tenant resolution behaves identically locally and in production — no
staging DNS required.
docker compose (dev) starts an nginx proxy (see infra/nginx/dev.conf)
that routes *.localhost subdomains to the identity service and derives
X-Tenant-Slug from the subdomain. No /etc/hosts edits are needed on
most machines: modern OSes resolve *.localhost to 127.0.0.1 automatically.
If yours doesn't, add the sample tenants to your hosts file instead
(127.0.0.1 acme.localhost globex.localhost).
# Boot the full stack (Postgres, Redis, identity service, nginx)
docker compose -f infra/docker/docker-compose.yml -f infra/docker/docker-compose.dev.yml up -d
# Hit two different fake tenant subdomains
curl -s http://acme.localhost/api/v1/health
curl -s http://globex.localhost/api/v1/health
# Both reach the identity service; the first carries X-Tenant-Slug: acme,
# the second X-Tenant-Slug: globex. Watch per-subdomain traffic with:
docker logs -f skyrict-nginxPath-based fallback — for environments without wildcard DNS, prefix the path with the tenant slug. Nginx strips the prefix and injects the header:
# http://localhost/acme/login -> /api/v1/auth/login + X-Tenant-Slug: acme
# http://localhost/acme/api/v1/health -> /api/v1/health + X-Tenant-Slug: acme
curl -s http://localhost/acme/api/v1/healthPort 80 already in use? Set a different host port — e.g. add
NGINX_PORT=8080 to infra/docker/.env (or export it in your shell), then
use http://acme.localhost:8080/docs.
The service resolves the tenant once per request in middleware: in staging/production from the
Hostsubdomain (first label ofIDENTITY_BASE_DOMAIN, e.g.acme.skyrict.com→acme), and in dev/test from theX-Tenant-Slugheader that nginx injects — there is no bypass path in any environment. The resolved tenant is stored inTenantContextand cross-checked against the JWTtenant_idclaim on every authenticated request; a mismatch is rejected with 401 (RFC 7807application/problem+json). See the identity service README for details.
# Python deps
uv sync
# Frontend deps
cd apps/web && pnpm install
# Boot infrastructure (Postgres, Redis)
docker compose -f infra/docker/docker-compose.yml up -d
# Kafka is intentionally deferred — see "Roadmap & Scope" below.
# Run migrations
make migrate
# Start identity service
make dev# Install git hooks (run once after clone)
./scripts/setup-hooks.sh # Unix/macOS
.\scripts\setup-hooks.ps1 # Windows
# Common tasks
make setup # Install deps, create DB, run migrations
make dev # Start identity service in dev mode
make dev-web # Start Next.js dev server
make dev-all # Start everything
make test # Run all tests
make test-unit # Unit tests only
make test-cov # Tests with coverage
make lint # Ruff + mypy
make format # Auto-format code
make migrate # Run pending Alembic migrations
make migrate-create MSG="add users table" # Create new migration
make seed # Load reference data
make build # Build Docker image
make check # Full CI check (lint + test)
make clean # Remove build artifacts
make help # Show all available targets./scripts/setup-hooks.sh # Unix/macOS
.\scripts\setup-hooks.ps1 # WindowsPre-commit hooks: Ruff lint, Ruff format, mypy, YAML/JSON/TOML validation, large file check, direct push block, conventional commit lint.
See docs/setup/branch-protection.md for required GitHub repository settings to enforce PR-only workflow, required reviews, and CI checks.
Not all of these exist yet — this is the intended end state. Today only identity is in active development.
services/
├── identity/ # Auth, JWT, OAuth2, RBAC, multi-tenancy (in active development)
├── core/ # ERP domain (finance, inventory, procurement) (planned)
└── intelligence/ # Signal collection, NLP, scoring, knowledge graph (planned)
Future (aspirational — not yet explicitly scoped):
services/
├── agents/ # LLM orchestration, tool registry, guardrails
└── analytics/ # OLAP queries, materialized views
Every domain service emits structured events to Kafka. No direct database reads between services.
Topic naming: {domain}.{entity}.{action}
Examples:
identity.user.created
identity.auth.login_success
inventory.stock.level_changed
finance.journal_entry.posted
Row-Level Security (RLS) on PostgreSQL. Every query is scoped to the current tenant via SET app.current_tenant_id. Tenant context flows through a ContextVar, not function parameters.
Skyrict is deliberately MVP-first: ship a small, secure, well-tested core before expanding scope. The following are intentionally deferred until a concrete need justifies them: SSO (SAML/OIDC), OPA policy engine, HashiCorp Vault, Kafka event bus (once 3+ services need decoupled async events), SCIM provisioning, and adaptive risk scoring.
See CONTRIBUTING.md for development workflow, code standards, and PR process.
To report a vulnerability, see SECURITY.md. Do not open a public issue for security reports.
Apache License 2.0. See LICENSE.
Skyrict trademarks and usage guidelines: TRADEMARK.md.