The repository-local automation platform that turns GitHub issues into validated pull requests, and a prompt into a running app — observable, gated, and self-hosted.
Olympus is a deterministic issue → PR factory for the repo it lives in: Archon workflows (YAML DAGs) drive triage → plan → implement → independent validation → controlled merge, with protected-path enforcement, required markers, non-zero evidence counts, and stop controls. One clone, one command, and a coding agent is wired to your OmniRoute gateway — ready to run factory workflows without re-implementing identity, secrets, billing, or storage. Studio adds the other direction: describe an app in the browser and watch it build — plan first, then a real container running the result — and export it to the factory as a build-requests/ spec, so a build you liked becomes factory input instead of stopping at the preview. /admin puts the deployment's own state on one read-only page.
| Area | Change |
|---|---|
/admin |
The deployment panel. Every failure this deployment ever had already had a script that diagnosed it — factory/doctor.py, gateway-edge-check.py, build-model-check.py, build-runner.py --list — and not one was reachable from a browser, so the person who noticed the symptom was never the person who could run the script. /admin is that as a read-only page: the checks with the fix named, the gateway door and its latency, the runner heartbeat and queue, recent jobs, built apps, and the access/tenancy posture. The door check is the one that earns it — an OMNIROUTE_BASE_URL pointing at the gateway's own :20128 on loopback compiles, resolves, and inside the container is Studio itself; the panel says that out loud and points at the SSO proxy on :20129 instead. Gated by OLYMPUS_ADMIN_GROUPS, polled every 20s, and it writes nothing. |
| Plan before build | Studio no longer assumes a stack. A planning turn (/api/plan → scripts/project_plan.py) decides the language, the install/build/start commands, the port the app listens on, the files it will contain, and its data target — its own container's database, or the self-hosted Convex Atlas runs. The plan is shown for confirmation before a line of code is written, and three things then have to agree on it: the agent builds to it, package-project.py writes the Dockerfile from it, and app-runtime.py runs the container on it. Change the prompt behind a plan and it is shown as out of date rather than silently confirmed. |
| Live previews + Preview It | The Preview tab renders generated files immediately in a sandboxed frame as the model writes; Preview It additionally packages and runs the project as a real runtime at <slug>-preview.<suffix>. Neither action registers the project's own name; only Publish It does. |
| One gateway door | OMNIROUTE_BASE_URL is http://192.168.1.46:20129/v1 — the Authentik SSO proxy in front of the platform's one OmniRoute. make gateway-auth-mode leaves the gateway with no gate of its own, so its :20128 is published on that host's loopback and bridge alone; /v1 is refused by edge rule on the public name, because this gateway does not validate the API key and the public name would otherwise hand out unauthenticated inference. |
| Tenancy | With CONTROL_PLANE_INTERNAL_URL + CONTROL_INTERNAL_TOKEN set, every Studio turn is spent on the signed-in user's own gateway key: identity resolved, quota gated before dispatch, usage recorded after, and audit rows for build/publish/export. The library follows the control-plane account, and an existing subject-keyed library is adopted in place. |
| Build runner | The account is probed, not assumed — a build runs a coding agent inside Codex's bubblewrap sandbox, and bubblewrap needs unprivileged user namespaces. Where they work the installer uses a dedicated olympus-builder account; where they are denied (including container setups) it stays root, because a non-root runner there means an unsandboxed agent rather than a safer one. Either way the agent stays sandboxed, and a cancel signals the whole process group. |
| BuildKit | scripts/buildx is the one command every packager runs — docker build when the daemon has no buildx, a named builder when BUILDX_NAME is set, and --check prints which builder a host will actually use instead of leaving it to be inferred later. |
| SecretOps | Infisical is replaced by Cerulean Vault (KV v2); infisical:// becomes vault://, and the bootstrap helper is scripts/omniroute-vault.sh. |
| Security | scripts/secret-scan.py fails the build on secret-shaped files; the Studio session and Vault token are scoped per stack. |
Full history and what is open: docs/roadmap.md — also on the landing page.
| Problem | Olympus answer |
|---|---|
| Issues stall between triage and a trustworthy PR | Deterministic factory workflows (prime → implement → validate, plus regress and triage) with independent validation |
| Automation that silently skips checks or walks past missing evidence | Non-zero evidence counts, required markers, ratchet floors, and fail-closed behavior are enforced |
| Agents that touch governance or secrets as ordinary work | Protected paths, secret-shaped-file blocks, and bounded PR size — fix the source, never the harness |
| Heavy model inference that heats the local CPU | 100% of heavy inference routed to free cloud models via the OmniRoute gateway (Codex auto/coding + Hermes 3 via OpenRouter), local Ollama bypassed |
| No visibility into autonomy, blockers, or held work | factory/doctor.py, factory/trigger.py --status, and the Studio /admin panel report readiness, autonomy, evidence, and what is held |
| Building a small app means leaving the platform for a chat window | Studio puts plan → prompt → files → running preview in the browser, behind the same gateway, OIDC and secret rules |
| "It's not working" arriving as a screenshot | The failure scripts are a page now, each check naming its own fix |
About Olympus — a repository-local AI software factory built with three upstream frameworks vendored under
core-modules/— OmniRoute (cloud routing gateway), Archon (YAML DAG workflow engine), and the AI Software Factory (SDLC scheduling and task consumer). Those point at theinnotelincmirrors on purpose: the upstream URLs this project originally referenced (inotex/omniroute,JohanLi233/archon,Andy-Zhouelect/AI-Software-Factory) are 404 — see UPSTREAMS.md for provenance, pinned SHAs, licenses and how to re-sync a mirror. The local CPU stays cool because the coding brain (Codex via OmniRouteauto/coding, Responses API) and the Telegram frontend (Hermes 3 70B via OpenRouter Free) never load weights locally — they run behind the gateway (Telegram atnousresearch/hermes-3-llama-3-70b:free). Landing page: innotelinc.github.io/olympus
- Owns: repository automation (issue → watched workflow → open PR), validation and safety (protected paths, required markers, evidence counts, stop controls), and operational visibility (
factory/doctor.py,factory/trigger.py, Studio/admin) - Owns: the five Archon factory workflows and the harness as the definition of "working" — the harness is never edited to make a check pass
- Provides: a one-command agent-ready clone (
bash scripts/bootstrap.sh) and an interactive Telegram surface for issue → fix laps - Provides: Studio — the browser build surface: plan first, then describe an app in plain language, watch it build, run and publish it, all against the same OmniRoute gateway (
make studio-dev) - Provides: the installer, the compose stacks, the landing page and this documentation — this repository is where an operator gets a working factory, not where its governance lives (see What this repo does and does not contain)
- Fast lane: Issue → Fix PR in ~35 minutes including autonomous code review
- Classification: FactoryOps — see docs/stack.md
Three entry points. Pick one — they are independent, and make help lists every target.
git clone https://github.com/innotelinc/olympus.git
cd olympus
bash scripts/bootstrap.sh # idempotentgit clone https://github.com/innotelinc/olympus.git
cd olympus
make setup # preflight + .env with generated secrets
$EDITOR .env # OMNIROUTE_* / OIDC_* / VAULT_* — see .env.example
make docker-up # builds ghcr.io/innotelinc/olympus:local + starts
make docker-logs # tail factory + gateway logsmake studio-install # install web/studio dependencies (npm ci)
make studio-dev # dev server → http://localhost:3001
make studio-test # vitest: parser, plan, gateway route, OIDC flow, admin
make studio-export-dir # let Studio write build-requests/ specs (uid 1001)
make studio-build-queue-dir # let Studio queue builds (uid 1001)
# "Build it": Studio's build runs on the host, not in its own container.
# Studio's image is a traced Next.js bundle — no Archon CLI, no Codex CLI, no
# checkout — so it queues a request and this service, which runs where the
# toolchain is, executes the same command `make app` does and records the result.
sudo make build-runner-install # systemd service (idempotent; --uninstall to remove)
make build-runner-check # what the runner will use: gateway, model, tools
make build-runner-list # the queue, and where each build got to
make build-model-check # can the configured model call a tool, twice over?
make test-runner # the runner's unit tests
make prune # old builds + finished queue files (ARGS="--yes" to delete)
# ...or inside the stack
docker compose up -d studio
# ...but when the gateway is published on loopback on this host, Studio has to
# share the host's network namespace. This target cannot get that wrong:
make docker-studio-upEvery failure this deployment has had already had a script that diagnosed it; the panel is those scripts on one read-only page, so the person who sees the symptom can see the cause.
https://<studio-host>/admin
It reads the gateway door and its latency, the runner heartbeat and queue, recent
jobs, built apps on disk, and the access/tenancy posture — plus a check list that
names the fix. It writes nothing, and it is gated by OLYMPUS_ADMIN_GROUPS
(comma-separated, exact match, re-checked per request; empty = any Studio user,
which is the right default for a single-operator deployment and is reported on the
page). See web/studio/README.md.
The builder has two front ends and only one of them had a UI. This is the other: one
window that queues a build and streams the status, the steps and the log that were
previously spread across make app, make build-runner-list and tail.
make tui # interactive
make tui ARGS="--list" # queued, running, finished
make tui ARGS="--once 'a weight tracker with a weekly chart'"It is a front end to the same builder, not a second one. The instruction becomes a
spec in build-requests/, and the runner builds it down the identical path make app
and the browser's Build It use — this adds a view, and no second implementation of a
plan or a generation prompt. Inside it, /preview <slug> and /publish <slug> queue a
delivery for an app already in builds/<slug>/, carrying that app's source the way the
browser does, and follow it.
Studio's two kinds leave by different doors, and the difference is whether the thing has state.
# A WEBSITE is static files: staged here, served by olympus-sites, named at the edge.
make sites-up # the server both kinds are fronted by
make sites-wildcard # once: *.studio.olympus.innotel.us + one certificate
make site-publish SLUG=todo-list # package, stage, and put it on a name
make site-check HOST=todo-list.studio.olympus.innotel.us
# An APP is a running service: React client + its own API + SQLite.
make app-package SLUG=weight-tracker # build the client, write the archive
make app-up SLUG=weight-tracker # image, container, loopback port, nginx vhost
make app-publish SLUG=weight-tracker # the three above, then the name
make apps-list
make app-down SLUG=weight-tracker # stop it, keep the databaseBoth are published through Cerulean + NPM under the same wildcard, and
studio-sites.py does not know which is which — the app's generated vhost does the
routing, so the edge never learns a per-app port. Each app's data lives on the host
at $OLYMPUS_APPS_ROOT/data/<slug>/, so a rebuild keeps it. See
docs/site-publishing.md.
Studio needs a gateway and (optionally) OIDC. make setup scaffolds .env; the keys that matter are OMNIROUTE_BASE_URL + OMNIROUTE_API_KEY for generation, and OIDC_ISSUER_URL / OIDC_CLIENT_ID / OIDC_CLIENT_SECRET / OIDC_REDIRECT_URI / STUDIO_SESSION_SECRET for sign-in. Auth stays off until it is configured — run make studio-oidc (or python3 scripts/authentik-studio-app.py) to create or repair the Cerulean Authentik application and provider for it. See web/studio/README.md for the full contract.
Generated apps are saved per signed-in identity, so a reload or a rebuild no longer loses them. With CONTROL_PLANE_INTERNAL_URL + CONTROL_INTERNAL_TOKEN set, the library follows the control-plane user id and each turn is spent on that user's own gateway key, with a quota check before it and usage recorded after it, rather than on the one shared OMNIROUTE_API_KEY. An existing subject-keyed library is adopted in place. See web/studio/README.md.
Then manufacture an app from a spec:
make new-request NAME=my-todo # → build-requests/my-todo.md
$EDITOR build-requests/my-todo.md
make app # local — or: make docker-app SPEC=build-requests/my-todo.md
make app SPEC=build-requests/my-todo.md REPLACE=1 # rebuild over an app already in ./builds
make builds # list ./builds (volume, gitignored)The workflow will not manufacture over an app it has already produced — a rebuild that
silently replaced builds/<slug> is how you lose the build you were comparing against.
REPLACE=1 is that consent, and it is the same consent Studio's own rebuild sends
({ "replace": true }). A retry needs it: the project a failed build is about is
exactly the one that already has output, so without it every retry of a project that got
far enough to write files was refused at the load node.
make app runs the archon-greenfield workflow (.archon/workflows/app/greenfield/)
through the Archon CLI: it resolves and bounds the spec, plans the stack, runs Codex
over the plan, asserts on the artifact rather than the exit code, and only then
writes a MANIFEST.json + README.md recording which spec (by SHA-256) and which model
produced the app. Its nodes declare runtime: uv, so uv is a hard requirement of this
path — ./setup.sh checks for it and make app says so plainly if it is absent. An agent that exits 0 having written nothing fails the run — worth
knowing because this gateway does that: Codex exits 0 even when its last request was
refused.
The stack is planned before the agent runs. One turn against the gateway decides the
language, the commands that install, build and start the project, the port it listens on
and the files it will contain, and writes plan.json into the app directory. Three
things read that file and must agree on it: the agent is told the plan and builds to it,
scripts/package-project.py writes the Dockerfile from it, and scripts/app-runtime.py
runs the container on its port. The plan also names the project's data target: its
own container's database by default, or the self-hosted Convex that Atlas runs when a
request genuinely needs live, shared state. A planning turn that produces no usable plan
stops the run. By hand: python3 scripts/project_plan.py --spec build-requests/my-todo.md.
The build node retries while the app directory is still empty, and switches model
between attempts: OMNIROUTE_MODEL first, then OMNIROUTE_MODEL_FALLBACK, then
auto/coding as a last attempt. Changing .env is how you change the build
model; exporting the variable does not survive, because Archon strips the repo's own
.env keys from a script node's environment and runs the workflow from a copy under
artifacts/runs/<id>/.
Pin a concrete, tool-calling model. A model that answers in prose still "completes" while writing nothing, which shows up as a build that runs for minutes and leaves an empty directory with no error to read:
auto/codingis a combo that walks the whole gateway catalogue —Trying model 1109/1388before it answered — so which brain finishes a build is luck.- A connection count is not quota: of ten connections recovered here, agentrouter was
402 budget pool exhausted, openrouter out of credits and openai429 no credits, and the gemini free tier cools down for 15–23 minutes after a burst.
make build-model-check does the check for the whole configured chain — two turns,
since the failure that cost the most here was on the second one — and exits 1 when a
build would exit 0 having written nothing. scripts/install-token-check-timer.sh TARGET=build-model alerts on it daily, and TARGET=gateway-backup keeps the gateway's
provider connections and the key that decrypts them in Vault on the same schedule.
The capacity story and the options for fixing it are in
docs/build-model.md — worth reading before adding credentials.
Docker also runs the same push manufacture trigger in CI: .github/workflows/olympus-app-builder.yml
(on.push.paths: build-requests/*.md).
That job can only build on a runner that can reach the gateway, and the gateway's API is
LAN-only by design. NPM refuses /v1 on every public name — gateway.olympus.innotel.us
included, which answers 403 with or without a key (see
docs/gateway-sso.md) — so a GitHub-hosted runner cannot reach it at
any URL. The job runs on vars.OLYMPUS_BUILD_RUNNER || ubuntu-latest; set that variable to
a self-hosted runner on the gateway's host, where the default
http://192.168.1.46:20129/v1 and the OMNIROUTE_API_KEY secret both work. Until one is
registered it reports the wiring gap, keeps the reason as an artifact
(.factory-ci/skipped.txt), and finishes green rather than turning red for it — and
make app is the working path.
A pushed spec is still built — by the host runner. scripts/build-runner.py sweeps
build-requests/*.md on a slower interval of its own (BUILD_SPEC_POLL_SECONDS, default
60; also once at start), fast-forwarding the checkout first (--ff-only, and only on a
clean tree), and queues every spec whose content this host has not manufactured through
the same submit() the CLI and Studio use. That way the host that can reach the gateway
is the one that builds a push, and no second path can disagree about what a request may
say. BUILD_SPECS=0 turns the sweep off and BUILD_SPECS_PULL=0 stops the pull. A push
whose build failed is deliberately not retried on the next pass — that retry is an
explicit act, in Studio or make app SPEC=... REPLACE=1.
The bootstrap is idempotent and does, in order:
- Installs what is missing: the OmniRoute CLI, the Codex CLI, the Claude Code CLI, and the Archon CLI.
- Checks that an OmniRoute server is reachable. If not, tries
scripts/omniroute-vault.sh(Vault-backed); otherwise prints how to start it and continues. - Creates an OmniRoute API key and stores it in
~/.omniroute/.env(never in the repo). - Wires both agents to OmniRoute: Codex →
~/.codex/config.toml+~/.codex/auth.json, Claude Code →~/.claude/settings.json. - Runs
python3 factory/doctor.pyso you can see readiness at a glance.
Then run the factory manually at autonomy level 0 (nothing unattended until a human has watched a real lap):
# Local
python3 factory/doctor.py
archon workflow run factory-implement --branch factory/impl-<n> "implement gh:issue:<n>"
archon workflow run factory-validate --branch factory/val-<n> "validate gh:pr:<n>"
# Docker
make docker-shell
python3 factory/doctor.py
# or from the host: docker compose exec olympus bash scripts/manufacture.sh build-requests/my-todo.mdThe engine it drives is a pin, not a checkout you keep. scripts/factory-pin.sh
runs the factory's own installer, which clones the Archon revision the factory's
manifest demands into ~/.cache/factory/archon/<sha> and copies its runtime into
this checkout; .factory/consumer.json records which revision that was, and
factory run refuses to start without it ("Integration pin required" — which
is what every manufacturing run said until the pin was first created here, on
2026-09-18). The install replaces factory/doctor.py and factory/trigger.py
with the factory's parallel stubs; this repo publishes its own pair (the doctor
backs the compose healthcheck), so the script restores them after installing and
tells you it did.
Autonomy is a ladder, and each rung needs a watched lap and explicit evidence
before it is turned on. Level 0 is a human starting every lap; level 1 is
.factory/loop.sh submitting exactly one scheduled shared workflow per tick
(factory tick reads .factory/schedule.json), kept alive by the
factory-timer unit. scripts/factory-dispatch.py is the gate between them —
the only thing that writes the schedule, records the evidence, and installs the
unit:
make dispatch-status # level, pin, workflows, evidence, blockers
# watch ONE lap end to end at level 0, then record it:
make lap-record WF=archon-triage RUN=<run-id> RESULT=pass WHO=<you>
make factory-arm WF=archon-lifecycle # refuses until every gate is clear
make factory-disarm # back to level 0 and stop the unit
python3 scripts/factory-dispatch.py --check # fails if a trigger exists without evidenceIt refuses to arm while the pin, the runtime, the provider login
(~/.factory-env, mode 600 — the unit sources it), the evidence or the stop
control (factory halt writes .factory/STOP) is missing, and every refusal
names the command that clears it. factory/trigger.py --status reports the same
state, so a status surface can never arm anything by accident.
| Step | Command / file | Notes |
|---|---|---|
| Prerequisites | make setup |
Preflight (git, curl, python3, node, docker where needed), installs the attribution guard hooks, generates .env with fresh secrets |
| Environment | .env.example → .env |
make setup never overwrites an existing .env; new keys are appended on upgrade. make env-sync reports any key the example documents that .env has never mentioned (exit 2), make env-sync-write appends them with the example's own comments. Neither edits, reorders or removes a line already there, and a key present but commented out counts as present |
| Gateway | OMNIROUTE_BASE_URL, OMNIROUTE_API_KEY |
The gateway is a shared platform service and this stack starts none — the single OmniRoute runs in Group 2 (2-voice/), on the Cerulean/trust host 192.168.1.46, so one provider pool serves every platform. The door is the Authentik SSO proxy in front of it, :20129: make gateway-auth-mode leaves the gateway with no gate of its own, so its own :20128 is published on that host's loopback and bridge alone and is never dialled across a network. Default OMNIROUTE_BASE_URL=http://192.168.1.46:20129/v1; on the gateway's own host a container uses http://host.docker.internal:20129/v1 and a host-mode caller http://127.0.0.1:20129/v1 (with compose.host-gateway.yml — make docker-studio-up). Not the published name: /v1 is refused there by edge rule (make gateway-edge --deny-path /v1), because this gateway does not validate the API key and the public name would otherwise hand out unauthenticated inference. See docs/gateway-sso.md |
| SecretOps | compose.vault.yml + scripts/vault-bootstrap.py |
Cerulean Vault (KV v2). VAULT_ADDR / VAULT_TOKEN / VAULT_PREFIX; values may be vault://<name> references resolved at startup. Tokens are scoped to this stack's own path |
| Identity | scripts/authentik-studio-app.py |
Creates the Studio application/provider in Cerulean Authentik; Studio is public until OIDC is set. The gateway dashboard's client is registered the same way |
| Gateway dashboard | make gateway-oidc, gateway-sso-up, gateway-auth-mode, gateway-edge, gateway-edge-check |
Puts the OmniRoute dashboard behind Authentik via an identity-aware proxy, restricted to a group, and publishes it — DNS record, certificate and NPM host — through Cerulean. gateway-auth-mode turns the gateway's own login off so Authentik is the only gate; because that makes the port's reachability the whole control, it checks the binding first (loopback plus this host's own docker0, never a LAN address) and refuses otherwise. The check walks the public name link by link and names the first one that is broken. See docs/gateway-sso.md |
| Gateway state | make gateway-vault-backup, gateway-vault-check, gateway-vault-restore |
The gateway's provider connections and the key that decrypts them, into Cerulean Vault. --check exits non-zero when the backup has drifted from the live gateway, so it can go on a timer |
| Trust / edge | scripts/ (NPM + Cerulean) |
DNS and TLS for the public names are managed through Cerulean and NPM Edge; see docs/stack.md |
| Upgrade | git pull && make setup |
Idempotent; scripts/factory-pin.sh pins the factory's upstream SHAs. make setup ends with env-sync --write, so a release that adds a knob shows up in .env instead of running on a built-in default nobody can see |
| Verify | make doctor, make studio-test, make ps |
Readiness, Studio test suite, supporting-service status |
Not published in this repo.
MISSION.md,FACTORY.md,FACTORY_RULES.md,AGENTS.md,harness/,factory/*(beyondAPP_SPEC_TEMPLATE.md,doctor.pyandtrigger.py),.archon/workflows/factory/and.factory/state are deliberately gitignored — see What this repo does and does not contain. An agent-ready clone installs them; a plain clone of this repository has the installer without the governance.
This repository is the installer and operator surface for Olympus. .gitignore is the
contract, not an accident:
- Published:
scripts/(bootstrap, manufacture, Vault, secret scan, factory pin,buildx),factory/doctor.py,factory/trigger.py,factory/APP_SPEC_TEMPLATE.md,web/studio/,web/landing/,docs/,docker-compose.yml,compose.vault.yml,compose.host-gateway.yml,compose.gateway-sso.yml,Dockerfile,Makefile,UPSTREAMS.md - Not published (gitignored):
MISSION.md,FACTORY.md,FACTORY_RULES.md,harness/,.factory/runtime state,.archon/workflows/factory/, andcore-modules/*— the vendored upstreams are cloned bysetup.sh/bootstrap.shon first run, so provenance stays pinned in UPSTREAMS.md instead of drifting with a copy in git
If you are looking for the safety rules, the holdout contract, or the five YAML DAGs, they live in the source checkout of the factory — not in this distribution repo.
Autonomy is earned. The full, current roadmap is docs/roadmap.md — which is also rendered at innotelinc.github.io/olympus/#roadmap.
| Milestone | What it is | State |
|---|---|---|
| 0.1 — the builder | Studio, the TUI and the plan → stream → package → run → publish engine, with the build runner and the saved-app store | shipped |
| 0.2 — the operator surface | /admin, plan-before-build, automatic live draft previews, Preview It, one gateway door, tenancy, runner hardening |
in development |
| 0.3 — dispatch | Arm the dispatcher after a watched lap; publish-time observability | engine installed and gated — pinned to Archon 29f6a73d (18 workflows), make dispatch-status reports level 0 with the two remaining human gates (the provider login and the watched lap); publish-time observability next |
| later | Autonomy L2 (validate) and L3 (holdout + mutation ratchet); ONYX storage, on hold | later |
| Document | What it covers |
|---|---|
| docs/roadmap.md | The current roadmap — milestones, the open 0.2 items, and the L0–L3 autonomy ladder |
| web/studio/README.md | Studio — the build UI: the plan, the six deliveries, tenancy, the /admin panel, configuration, output contract, security posture |
scripts/olympus-tui.py |
The builder's terminal front end (make tui) — what it reads, the keys, and why it queues rather than planning or generating |
| docs/stack.md | This platform's role in the Innotel Platform Stack (FactoryOps), including SecretOps via Cerulean Vault (KV v2) and the vault:// reference convention |
| docs/gateway-sso.md | Putting the OmniRoute dashboard behind Cerulean Authentik, make gateway-auth-mode, and why the gateway cannot gate itself |
| docs/site-publishing.md | Studio's two kinds of build — an app (React + API + SQLite, one container per app) and a website (static) — the packaging/runtime/publish pipelines, previews, the plan's Convex target, and the ONYX (on hold) integration points |
| docs/host-migration.md | Consolidating Olympus onto 192.168.1.46 — the two-host split that made every sign-in fail with invalid_client while the local .env was correct |
| docs/build-model.md | The capacity story behind the build model: which connections were measured as unusable, what make build-model-check proves and does not, and the durable fix |
scripts/verify-sso.py |
The Studio sign-in test — client credentials at the token endpoint, the edge's forward target, anonymous refusal, and a full authorization-code flow |
| UPSTREAMS.md | Vendored upstream mirrors (Archon, AI Software Factory, skills, OmniRoute, archon-cli) — provenance, pinned SHAs, licenses, recovery and re-sync |
| factory/APP_SPEC_TEMPLATE.md | The spec format make new-request scaffolds and the manufacture step reads |
.env.example |
Every knob the stack reads, grouped and commented (gateway, Studio, OIDC, Vault, Cerulean, NPM, Magnate) |
Makefile |
The full target list — make help |
MISSION.md, FACTORY.md, FACTORY_RULES.md, AGENTS.md, harness/END-TO-END.md, .factory/holdout/HOLDOUT.md |
Scope, operations, safety rules and the holdout contract — in the source checkout, gitignored here |
Olympus is licensed under the GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later). See LICENSE for the full text. Upstream frameworks under core-modules/ retain their own licenses in-tree.
Olympus · FactoryOps · Innotel Platform Stack — one job per platform, platform services consumed by business functions.