This repo is a monorepo: core stays stable, apps iterate fast, and shared packages form the only legal bridge.
syris/
├── core/
│ └── syris_core/ # SYRIS core (Python, uv)
│ ├── pyproject.toml
│ ├── alembic.ini
│ ├── src/syris_core/ # import namespace
│ └── tests/
├── apps/
│ ├── dashboard/ # mission control (Next.js)
│ ├── docs/ # internal docs (Next.js + Fumadocs)
│ └── nutrition/ # standalone app(s)
├── packages/
│ ├── shared-types/ # cross-app contracts (TS/JSON schema)
│ ├── api-client/ # typed client for core API (TS)
│ └── ui/ # optional shared UI primitives
├── archive/ # deprecated modules (read-only)
└── ops/ # deployment and ops artifacts
src/syris_core/
├── __init__.py
├── main.py # Boot: wire all components, start loops
├── config.py # Typed settings (Pydantic BaseSettings)
│
├── schemas/ # Pure Pydantic v2 — no DB, no logic
│ ├── __init__.py
│ ├── common.py # Enums, ErrorDetail, shared value types
│ ├── events.py # MessageEvent, RoutingDecision, GateSpec
│ ├── tasks.py # Task, Step, RetryPolicy, StepOutcome
│ ├── tools.py # ToolCall, ToolResult, ToolCallContext,
│ │ # RegisteredTool, ToolHealth, TrustPolicy
│ ├── audit.py # AuditEvent
│ ├── approvals.py # Approval
│ ├── schedules.py # Schedule
│ ├── rules.py # Rule, Condition, Action types
│ └── health.py # SystemHealth, Alarm
│
├── storage/ # DB layer (PostgreSQL)
│ ├── __init__.py
│ ├── db.py # Engine, session factory, connection config
│ ├── models.py # SQLAlchemy ORM models (all tables)
│ ├── repos/ # One repo per aggregate root
│ │ ├── __init__.py
│ │ ├── events.py
│ │ ├── audit.py
│ │ ├── tasks.py
│ │ ├── tools.py # tool_calls, tool_results, idempotency_outcomes
│ │ ├── approvals.py
│ │ ├── schedules.py
│ │ ├── watchers.py
│ │ ├── rules.py
│ │ ├── health.py # system_health, alarms
│ │ └── projections.py # proj_* tables read/write
│ └── migrations/ # Alembic
│ ├── env.py
│ └── versions/
│
├── pipeline/ # The three-stage pipeline
│ ├── __init__.py
│ ├── runner.py # Main loop: normalise → route → execute
│ ├── normaliser.py # Raw payload → MessageEvent + audit
│ ├── router.py # Orchestrates routing layers in order
│ └── executor.py # Dispatches to fast/task/gated/sandbox
│
├── routing/ # Router internals (peer to pipeline/)
│ ├── __init__.py
│ ├── filters.py # Hard filters: dedup, spam, quiet hours
│ ├── fastpath.py # Deterministic intent matching
│ ├── rules_eval.py # Condition evaluator for Rule objects
│ └── llm_fallback.py # LLM-based routing (last resort)
│
├── tasks/ # Task engine
│ ├── __init__.py
│ ├── engine.py # Claim → execute → checkpoint loop
│ ├── step_runner.py # Execute one step, handle outcomes
│ ├── state.py # State machine enforcement
│ └── recovery.py # Startup reconciliation
│
├── tools/ # Tool runtime
│ ├── __init__.py
│ ├── registry.py # ToolRegistry: register, lookup, health
│ ├── executor.py # Scope → risk → gate → idempotency → call
│ ├── idempotency.py # Outcome store operations
│ ├── base.py # BaseTool ABC
│ └── builtin/
│ └── noop.py # NoopTool for testing
│
├── safety/ # Safety layer
│ ├── __init__.py
│ ├── autonomy.py # Read/write current level + history
│ ├── risk.py # Risk classifier + adjusters
│ ├── gates.py # Gate matrix + override evaluation
│ └── dryrun.py # Preview protocol
│
├── scheduler/ # Schedules only
│ ├── __init__.py
│ └── loop.py # Scheduler tick loop
│
├── watchers/ # Watcher subsystem (top-level peer)
│ ├── __init__.py
│ ├── loop.py # Watcher tick loop
│ ├── base.py # BaseWatcher ABC
│ └── heartbeat.py # HeartbeatWatcher
│
├── rules/ # Rules engine (top-level peer)
│ ├── __init__.py
│ ├── engine.py # Load rules, evaluate, dispatch actions
│ └── cache.py # In-memory cache with TTL + invalidation
│
├── mcp/ # MCP integration (top-level peer)
│ ├── __init__.py
│ ├── connection.py # MCPConnectionManager
│ ├── provider.py # MCPProvider: discovery → registry sync
│ ├── adapter.py # MCPToolAdapter(BaseTool)
│ └── trust.py # TrustPolicy schema + loader
│
├── adapters/ # Inbound/outbound adapters
│ ├── __init__.py
│ ├── inbound/
│ │ ├── __init__.py
│ │ └── base.py # InboundAdapter ABC
│ └── outbound/
│ ├── __init__.py
│ └── base.py # OutboundAdapter ABC
│
├── observability/ # Audit, projections, health
│ ├── __init__.py
│ ├── audit.py # AuditWriter — sole emit point
│ ├── projections.py # Sync projection updaters
│ ├── health.py # SystemHealth writer
│ └── alarms.py # Alarm creation + dedup + lifecycle
│
├── secrets/
│ ├── __init__.py
│ └── store.py # SecretsStore protocol + Fernet impl
│
├── api/ # FastAPI
│ ├── __init__.py
│ ├── app.py # FastAPI app factory
│ ├── deps.py # Dependency injection (session, services)
│ └── routes/
│ ├── __init__.py
│ ├── status.py # /health, /state
│ ├── events.py # /events
│ ├── audit.py # /audit, /artifacts/{id}
│ ├── tasks.py # /tasks CRUD + cancel/pause/resume
│ ├── approvals.py # /approvals + approve/deny
│ ├── schedules.py # /schedules CRUD
│ ├── watchers.py # /watchers
│ ├── rules.py # /rules
│ ├── integrations.py # /integrations
│ ├── controls.py # /controls/pause, resume, autonomy
│ └── alarms.py # /alarms + ack/resolve
│
└── workers/ # Milestone 7 — skeleton only
├── __init__.py
└── manager.py
schemas/ contains Pydantic v2 data contracts only — no DB access, no logic. ORM models live in storage/models.py. routing/ is separate from pipeline/ so that fastpath.py and rules_eval.py can be unit-tested without instantiating the full pipeline.
Anything under apps/* is a standalone application and must not import from core/*.
Allowed: apps/* → packages/*
Not allowed: apps/* → core/*
All integration code lives under core/syris/ because integrations deploy together with the control plane, share the secrets and scopes policy, and participate in the same audit and trace runtime.
storage/repos/ contains one repository object per aggregate root. Pipeline and task engine code imports from repos, not from the ORM directly. This keeps the DB layer swappable — change repo internals, callers do not change.
Core:
uv sync
uv run python -m syris.main # control plane + API server
Apps:
bun run dev # in each app directory (dashboard / docs / nutrition)