Skip to content

Latest commit

 

History

History
134 lines (105 loc) · 6.68 KB

File metadata and controls

134 lines (105 loc) · 6.68 KB

Architecture — chrono-ornn

For API v1 and architecture conventions, see CONVENTIONS.md. Active refactor work is tracked under the Refactor milestone.

Project Overview

chrono-ornn is an AI skill platform. Users create, publish, search, and execute AI skills (packaged prompts + scripts) via a web UI or API. Authentication and LLM calls go through NyxID. Script execution runs in chrono-sandbox.

External Services

Service How ornn-api talks to it
NyxID JWT verification (JWKS), API key introspection, LLM Gateway (Responses API)
chrono-sandbox POST /execute — script execution with env vars, dependencies, file retrieval
chrono-storage Upload/download/delete skill packages (presigned URLs)

Skill Format

  • Available runtimes: node, python
  • Frontmatter field for dependencies: runtime-dependency
  • Category types: plain, tool-based, runtime-based, mixed
  • Output types: text (stdout), file (generated files retrieved via glob)

Audit + analytics (PostHog)

Issue #271 collapsed every observability surface in Ornn — the universal API audit middleware (#245), the activities Mongo collection, and the OpenTelemetry placeholder section — into a single PostHog-driven pipeline. There is no custom audit code in Ornn anymore; everything flows through the posthog-node SDK and is viewed in the PostHog dashboard.

Event taxonomy

Backend events (server-emitted, every event carries source: "api" so dashboards can disambiguate from frontend events of the same name):

event when properties
api.request every authenticated /api/v1/* request userId, callerType, method, path, routePattern, status, durationMs, sourceIp (truncated /24 IPv4, /48 IPv6), requestId
api.error sampled 5xx responses statusCode, errorCode, method, path, requestId
api.skill.pull every skill package materialization callerType, skillId, skillName, skillVersion
api.skill.published skill create + version publish skillId, skillVersion, isNewSkill
user.login / user.logout session open / close
skill.created / .updated / .deleted / .version_deleted mutation routes skillId, skillName, version, adminAction?
skill.visibility_changed / .permissions_changed visibility + sharing flips skillId, isPrivate, sharedWithUsers, sharedWithOrgs, writeGrants (count of write grants, #1123)
skill.ownership_transferred ownership handed to another user (#1123) skillId, skillName, priorOwnerId, newOwnerId
skill.refresh / .source_linked / .source_unlinked source-pointer ops skillId, repo, ref, commit
skill.nyxid_service_tied / .agentseal_rescanned tie + admin-rescan skillId, isSystemSkill, score
settings.exported / .imported settings IO schemaVersion, aggregateStatus, dryRun, sections

Frontend events (browser SDK — ornn-web/src/lib/analytics.ts) carry auto-pageview + cookie-consent state and the typed event union in that file. Identity is set via posthog.identify(userId, traits) on every NyxID login.

Caller-type detection

api.request is emitted from apiRequestTrackingMiddleware mounted on /api/v1/* AFTER proxyAuthSetup. callerType derives from auth shape:

auth shape X-Ornn-Caller callerType
browser session (NyxID OAuth cookie / browser-scope Bearer) web
NyxID forwarded user-access token (agent via NyxID proxy) api
anonymous system / playground matches header
anonymous other web

The header is informational only. Source IP is read from X-Forwarded-For (first hop), falls back to X-Real-IP, then truncated to /24 (IPv4) or /48 (IPv6) before emit.

Configuration

PostHog config lives in the admin telemetry settings section. Backend reads it once at boot (bootstrap.ts) and falls back to env vars when the DB section has no API key set:

field env fallback meaning
postHogEnabled POSTHOG_ENABLED master switch — off forces NoopTracker even with a key
postHogApiKey POSTHOG_API_KEY public project key (phc_…); empty disables
postHogHost POSTHOG_HOST ingest host (e.g. https://eu.i.posthog.com)
postHogProjectId POSTHOG_PROJECT_ID informational, surfaced in log lines
postHogErrorSampleRate POSTHOG_ERROR_SAMPLE_RATE [0,1] sampling for api.error

Admin DB is canonical: a non-empty postHogApiKey in the section makes the entire DB record authoritative; otherwise env wins. Restart-required for changes to apply (the SDK is initialized once at boot).

Failure modes accepted

  • No body archive. Request/response bodies are not captured. Forensic body-replay post-incident is not possible. The previous MinIO-offload pipeline (#245) was removed.
  • Audit retention = PostHog retention. Cloud free tier is approximately 1 year of events; paid extends. Self-hosted PostHog retains as long as the storage volume allows.
  • PostHog-side outages drop events that miss the in-process buffer. The drain on shutdown() flushes the buffer; sigterm during a backlog can lose tail events.

Viewing data

There is no in-Ornn activity feed UI. Admins use the PostHog dashboard for the full event explorer, funnels, retention, and SQL queries. The Ornn admin dashboard at /admin deep-links to the PostHog Activity / Insights views via ornn-web/src/lib/postHogLinks.ts, which translates the configured ingest host (<region>.i.posthog.com) into the matching dashboard host (<region>.posthog.com).

What about OpenTelemetry?

Considered and deferred (issue #271 discussion). For Ornn's current single-service architecture and the requirements covered here (per-request audit, user activity, who-called-what), PostHog alone is sufficient. OpenTelemetry's value (distributed tracing, metrics histograms) doesn't justify standing up a collector + Tempo / Loki / Jaeger today. Reopen as a separate issue if/when the architecture splits across services or a concrete tracing pain point appears.

User directory

The unified users Mongo collection (built in #271, replaces activities + admin_users + users_meta) is fed lazily by proxyAuthSetup.onAuthSeen on every authenticated request. It is NOT audit data — it's an identity cache backing the skill-permissions typeahead, the admin user list, and the dashboard role partition. NyxID stays authoritative for permission checks; this collection is display + indexing only. See ornn-api/src/domains/users/repository.ts.