Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# Contributing to DurinDoor

Thanks for helping improve DurinDoor.

- Read the full contribution guidelines in [CONTRIBUTING.md](../CONTRIBUTING.md).
- For the development workflow, build instructions, review expectations, and provider contribution notes, see [docs/contributing/index.mdx](../docs/contributing/index.mdx).
- For the development workflow, build instructions, review expectations, and provider contribution notes, see [internal/docs/index.mdx](../internal/docs/index.mdx).

Pull requests must target the `main` branch. Pull requests opened against other branches will be closed unless explicitly requested by a maintainer.
7 changes: 3 additions & 4 deletions .github/pr-templates/postgres-engine.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,9 @@ $ npx vitest run unit/api/settings-database-route.test.js

## Doc coverage

- `docs/operations/postgres.md` — operator runbook (PG 16/17/18/19, version policy, cutover, fallback, rollback, secrets, upgrade notes).
- `docs/development/postgres.md` — developer guide (module layout, dialect helper, generator, capability gate, adapter contract, cutover lock, secrets, cross-fork policy).
- `docs/development/postgres-research.md` — Phase 1 research deliverable (24-row per-version feature matrix + 8 `pg` driver gotchas).
- `docs/ARCHITECTURE.md` — Persistence section updated to mention the PG engine and the cutover pipeline.
- `docs/operations/postgres.mdx` — operator runbook (PG 16/17/18/19, version policy, cutover, fallback, rollback, secrets, upgrade notes).
- `internal/docs/postgres-migrations.mdx` — developer guide (module layout, dialect helper, generator, capability gate, adapter contract, cutover lock, secrets, cross-fork policy).
- `internal/docs/architecture.mdx` — Persistence section updated to mention the PG engine and the cutover pipeline.
- `CHANGELOG.md` — entry under 4.0.0.

## Baseline impact
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/release-prepare.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ name: Release Prepare
# contents:write + pull-requests:write on this repo) for the fully automated
# chain. Without it the workflow still works but prints a loud warning and
# the release PR must be checked/merged manually (see
# docs/development/release-process.md).
# internal/docs/release-process.mdx).
#
# Retry policy: the release branch content is fully derived from origin/main
# + the version, so if a previous run left a stale release/vX.Y.Z branch
Expand All @@ -28,7 +28,7 @@ name: Release Prepare
#
# If main advances while the release PR waits for review, close the PR and
# re-dispatch this workflow — it recomputes version, changelog, and branch
# from the latest main. See docs/development/release-process.md.
# from the latest main. See internal/docs/release-process.mdx.
on:
workflow_dispatch:
inputs:
Expand Down Expand Up @@ -146,7 +146,7 @@ jobs:
echo "::warning::Manual fallback: run the §6.4 checks locally (npm run lint,"
echo "::warning::cd tests && npm run test:ci, npx commitlint --from=origin/main"
echo "::warning::--to=HEAD), record them in the PR, and merge with a maintainer"
echo "::warning::account. See docs/development/release-process.md."
echo "::warning::account. See internal/docs/release-process.mdx."
echo "::warning::============================================================"
fi

Expand Down Expand Up @@ -181,7 +181,7 @@ jobs:

- **Scope:** version bump of the root and cli manifests + lockfiles, and the generated \`CHANGELOG.md\` section. No runtime code changes.
- **Test coverage:** no behavior change to cover; the release tooling itself is unit-tested in \`tests/unit/release-notes.test.js\`. The full \`test.yml\` gate runs on this PR (requires RELEASE_PAT so the PR event fires workflows).
- **Doc coverage:** process and rollback documented in \`docs/development/release-process.md\`.
- **Doc coverage:** process and rollback documented in \`internal/docs/release-process.mdx\`.
- **Baseline impact:** none — no test changes; \`tests/__baseline__/known-fails.txt\` untouched.
- **Wire-format / migration concerns:** none — manifests, lockfiles, and changelog only; stored API keys, \`[providers.9router]\` labels, \`X-Msh-Platform\` headers, and the \`~/.9router\` data dir are unaffected.

Expand All @@ -191,7 +191,7 @@ jobs:

**If main advances while this PR is open:** close this PR and re-dispatch Release Prepare; it recomputes the version and changelog from the latest main and replaces the branch.

Rollback: close this PR unmerged (nothing else happens), or after merge delete the GitHub Release + tag and revert the bump commit — see \`docs/development/release-process.md\`.
Rollback: close this PR unmerged (nothing else happens), or after merge delete the GitHub Release + tag and revert the bump commit — see \`internal/docs/release-process.mdx\`.
EOF

- name: Open release PR
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/release-tag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ name: Release Tag
# in both package manifests at the pushed commit. If a maintainer merges a
# release PR manually with a different title, tagging will NOT fire — run
# **Actions → Release Tag → Run workflow** with `version: X.Y.Z` as the
# documented fallback (see docs/development/release-process.md).
# documented fallback (see internal/docs/release-process.mdx).
#
# CRITICAL — token choice: events created with GITHUB_TOKEN do NOT trigger
# other workflows, so `release: published` (release.yml, the npm publisher)
# only fires when the Release is created with a PAT. Set the RELEASE_PAT
# secret (fine-grained PAT, contents:write on this repo) for the fully
# automated chain. Without it the Release is still created with
# GITHUB_TOKEN, but release.yml will NOT fire and the CLI must be published
# manually (see docs/development/release-process.md).
# manually (see internal/docs/release-process.mdx).
on:
push:
branches:
Expand Down Expand Up @@ -152,7 +152,7 @@ jobs:
echo "::warning:: gh release delete v\$VERSION --repo bloodf/durindoor --yes"
echo "::warning:: gh release create v\$VERSION --repo bloodf/durindoor --title v\$VERSION --notes-file release-notes.md --target \$TARGET_SHA"
echo "::warning::or publish the CLI manually: npm run cli:publish with NPM_TOKEN."
echo "::warning::See docs/development/release-process.md (Manual fallback)."
echo "::warning::See internal/docs/release-process.mdx (Manual fallback)."
echo "::warning::============================================================"

- name: Create tag and GitHub Release
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,7 @@ storybook-production-proof/

# Local design review captures; the design contract and tokens remain versioned.
.impeccable/review/

# Detailed AI documentation is source material, not the product build directory.
!internal/docs/product/
!internal/docs/product/**
3 changes: 2 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ This file is the contract for people changing DurinDoor, a fork of `decolua/9rou
- `open-sse/`: provider routing, translation, and executors.
- `cli/`: npm launcher published as `durindoor`.
- `website/`: public site plus a mocked dashboard demo.
- `docs/`: user and operator Markdown.
- `docs/`: published user and operator Markdown.
- `internal/docs/`: repository-only AI and maintainer references. Start with `internal/docs/README.md`; brand and porting guides are not published.
- `tests/`: Vitest suite. It is its own package, not wired to root `npm test`.
- `scripts/`: generators and CI checks, including `gen:registry-index` and `gen:agent-index`.

Expand Down
6 changes: 3 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# DurinDoor

DurinDoor is a self-hosted AI gateway that puts many LLM providers behind one OpenAI-compatible API. It is a fork of 9router. The look is LOTR-inspired.
DurinDoor is a self-hosted AI gateway for OpenAI Chat Completions, Responses, and Anthropic Messages, plus provider-dependent media and search routes. It is a fork of 9router. The public identity uses a fantasy gate, forest stone, silver, and emerald.

This file is a project overview. The contributor contract is `AGENTS.md` in this directory. Read that first.
This is an AI project overview. Read [AGENTS.md](AGENTS.md) for the contributor contract, then [internal/docs/README.md](internal/docs/README.md) for detailed implementation references and [the AI workflow](internal/docs/agent-workflow.md) for feature ports. Public user and operator instructions live under `docs/`. Internal references are not published by the website.

## Quick reference

Expand Down Expand Up @@ -97,6 +97,6 @@ Replace `<pr-title>` with the actual PR title; rewrite the title if it fails.

## Branch model

`main` is the default branch (post v2.2.0) and the source for both production releases and nightly pre-releases. Release flow: feature PR to `main`, then tag (`vX.Y.Z`). `release.yml` publishes to npm. `docker-publish.yml` builds multi-arch images. `nightly.yml` runs daily at 02:00 UTC and publishes a `nightly-YYYY-MM-DD` GitHub pre-release.
`main` is the default branch (post v2.2.0) and the source for both production releases and nightly pre-releases. Release flow: feature PR to `main`, then tag (`vX.Y.Z`). `release.yml` publishes to npm. `docker-publish.yml` builds multi-arch images. `nightly.yml` declares a daily 02:00 UTC schedule and a `nightly-YYYY-MM-DD` GitHub pre-release. Its header notes that repository settings disable the schedule during development recovery. Verify the enabled state before assuming nightly runs are active.

Default PR target is `main`. PR checklist, commit rules, and test workflow are in `AGENTS.md`.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Contributing to DurinDoor

The contributor guide is at [https://durindoor.vercel.app/docs/contributing](https://durindoor.vercel.app/docs/contributing).
The contributor guide is at [internal/docs/index.mdx](internal/docs/index.mdx).

Open an issue before large changes. Pull requests target `bloodf/durindoor:main`. Submit changes to this repository.

Expand Down
2 changes: 2 additions & 0 deletions PRODUCT.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ The public website persuades developers to try the real dashboard with sample da
The user pinned a green fantasy identity inspired by the entrance to Moria: carved stone, silver engraving, emerald light and visibly opening doors. Keep readable technical documentation and a truthful dashboard distinct from the expressive marketing presentation. No endpoint addresses in the marketing hero. The usebeans.app reference informs clear product examples and an actual interactive app preview.

The user also references openbot.run for soft gradients, effects, and bento layouts. Apply this to truthful feature-mechanism illustrations, with asymmetric spans and emerald depth; preserve the carved gate and real demo.

Public documentation under `docs/` addresses users and operators with concise, complete task guides. AI and maintainer references under `internal/docs/` retain source ownership, implementation details, porting procedures, brand rules, and verification evidence. The website publishes only public docs and runtime image assets.
14 changes: 5 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ The dashboard opens at `http://localhost:20128/dashboard`. Sign in with your ini

In **Providers**, add an OAuth account, a provider API key, or a compatible local or remote endpoint. In **API Keys**, create a DurinDoor key and copy its secret.

Choose an available model in the dashboard or list the models exposed by your instance:
Choose an available model in the dashboard or list the models exposed by your instance. This catalog request does not verify your gateway key:

```bash
export DURINDOOR_API_KEY="YOUR_DURINDOOR_API_KEY"
Expand Down Expand Up @@ -176,7 +176,7 @@ Read [Connecting accounts](https://durindoor.vercel.app/docs/providers/connectin
The gateway also has endpoints for images, speech, embeddings, reranking, moderation, video, music, web search, and web fetch. Model support varies by provider. Use the [API reference](https://durindoor.vercel.app/docs/reference/api) for exact request bodies and response formats.

- The [MCP gateway](https://durindoor.vercel.app/docs/features/mcp-gateway) connects several MCP servers behind scoped gateway keys.
- [Realtime](https://durindoor.vercel.app/docs/features/realtime) uses OpenAI-shaped text WebSocket events. Audio is not supported.
- [Realtime](https://durindoor.vercel.app/docs/features/realtime) relays supported native provider protocols, including audio where available. Chat models use a text-only facade.
- [Media routes](https://durindoor.vercel.app/docs/features/media-routes) configure fallback order for calls that omit a model or use `auto`.
- The [proxy timeline](https://durindoor.vercel.app/docs/features/proxy-timeline) records redacted request hops when enabled. It is off by default.

Expand Down Expand Up @@ -211,17 +211,13 @@ SQLite is the default database. The dashboard supports an optional Postgres cuto
| Look up routes, flags, or settings | [Reference](https://durindoor.vercel.app/docs/reference) |
| Diagnose a failed request | [Troubleshooting](https://durindoor.vercel.app/docs/troubleshooting) |

The [product guide](PRODUCT.md) describes the gateway’s scope. The [design system](DESIGN.md) records the website and documentation identity. The [brand guide](https://durindoor.vercel.app/docs/contributing/brand-guide) covers the identity and future dashboard redesign.
The docs site covers installation, everyday use, deployment, and API reference.

## Contribute

Issues and pull requests are welcome. Pair behavior changes with a doc update and a test. Read [Contributing](https://durindoor.vercel.app/docs/contributing), the [Code of Conduct](CODE_OF_CONDUCT.md), and the [security policy](.github/SECURITY.md).
[Internal references](internal/docs/README.md) contain AI implementation context, feature porting procedures, and brand rules. These files are not published on the docs site.

Provider definitions live in [`open-sse/providers/registry/`](open-sse/providers/registry). Start with [`REGISTRY_TEMPLATE.js`](open-sse/providers/REGISTRY_TEMPLATE.js). Keep generated registry indexes generated.

## Visual identity

The identity pairs an emerald gate with silver lettering and forest stone. Cormorant Garamond carries the display lettering; Space Grotesk carries controls and documentation.
Issues and pull requests are welcome. Pair behavior changes with a doc update and a test. Read [Contributing](CONTRIBUTING.md), the [Code of Conduct](CODE_OF_CONDUCT.md), and the [security policy](.github/SECURITY.md).

## License and acknowledgments

Expand Down
6 changes: 3 additions & 3 deletions assets/brand/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Brand asset maintenance

The [DurinDoor brand guide](../../docs/contributing/brand-guide.mdx) is the canonical guide for logo use, current public colors, typography, motion, and future dashboard work. Keep brand rules there rather than duplicating a palette in this file.
The [DurinDoor brand guide](../../internal/docs/brand-guide.mdx) is the canonical guide for logo use, current public colors, typography, motion, and future dashboard work. Keep brand rules there rather than duplicating a palette in this file.

This directory owns the original logo SVGs, application icon, gateway illustration, identity board, and generated raster assets. Wordmark lettering is outlined from Cormorant Garamond at weight 600. The board is a presentation reference; production logos use the SVG originals.

Image-generation prompts are retained in `prompts.md`. Local public font files and their SIL Open Font License notices live in `website/public/home/fonts/`. Dashboard Inter files live in `public/fonts/`.
Image-generation prompts are retained in `internal/docs/brand-prompts.md`. Local public font files and their SIL Open Font License notices live in `website/public/home/fonts/`. Dashboard Inter files live in `public/fonts/`.

After changing a canonical asset, run these commands from the repository root:

Expand All @@ -13,4 +13,4 @@ node scripts/sync-brand-assets.mjs
node website/scripts/sync-public.mjs
```

The first command renders the existing project asset filenames and requires website dependencies for SVG rasterization. The second refreshes generated website assets, including the `/brand` copy. The website also runs the copy during `predev` and `prebuild`. Edit originals here, not the generated website copies.
The first command renders the existing project asset filenames and requires website dependencies for SVG rasterization. The second refreshes generated website assets, including the `/brand` copy. The website also runs the copy during `predev` and `prebuild`. Only runtime image files are published. Maintenance Markdown, prompts, and archives remain repository-only. Edit originals here, not the generated website copies.
17 changes: 13 additions & 4 deletions cli/README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
# DurinDoor CLI

The `durindoor` package installs and runs the DurinDoor self-hosted AI gateway.
The `durindoor` package installs and runs the self-hosted DurinDoor AI gateway.

Flags, tray, heap, DNS, and update behaviour: [CLI reference](../docs/reference/cli.mdx). Install methods: [Installation](../docs/getting-started/installation.mdx). Package: [npm](https://www.npmjs.com/package/durindoor). Image: [ghcr.io/bloodf/durindoor](https://github.com/bloodf/durindoor/pkgs/container/durindoor).
Use Node.js `20.20.2` and npm `10.8.2`. Start a local instance with an explicit loopback address:

```bash
export JWT_SECRET="$(openssl rand -hex 32)"
export INITIAL_PASSWORD="CHANGE_ME_STRONG_PASSWORD"
npm install --global durindoor
durindoor
durindoor --host 127.0.0.1
```

Requires Node.js 20.20.2. License: [MIT](LICENSE).
Replace the password before running the command. Keep the signing secret stable across restarts. Open `http://localhost:20128/dashboard`, sign in, connect a provider, and create a gateway key.

The CLI performs startup cleanup before launching. Use the [CLI reference](../docs/reference/cli.mdx) for flags, updates, tray behavior, port handling, and recovery. Follow [Installation](../docs/getting-started/installation.mdx) for other install methods and first-run configuration.

- [First request](../docs/getting-started/first-request.mdx)
- [npm package](https://www.npmjs.com/package/durindoor)
- [Docker image](https://github.com/bloodf/durindoor/pkgs/container/durindoor)
- [MIT license](LICENSE)
12 changes: 6 additions & 6 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ services:
PORT: "20128"
HOSTNAME: "0.0.0.0"
NODE_ENV: production
# The PG engine is opt-in. To enable it, set DURINDOOR_PG_URL in
# .env (or pass the connection string in the dashboard) and run
# a cutover from the Settings > Database page. The env var is
# read at boot; the dashboard secret is read from
# /app/data/durindoor-secrets.json (mode 0600) when the env var
# is absent.
# Existing SQLite installs: leave PG_URL unset or empty, run cutover
# in Settings > Database, then optionally set an explicit boot URL.
# Fresh direct-Postgres installs: set DURINDOOR_PG_URL before boot.
# A nonempty URL selects Postgres before SQLite settings load.
# Empty values are normalized to unset; dashboard credentials live
# in /app/data/durindoor-secrets.json (mode 0600).
DURINDOOR_PG_URL: ${DURINDOOR_PG_URL:-}
DURINDOOR_PG_SSLMODE: ${DURINDOOR_PG_SSLMODE:-prefer}
DURINDOOR_PG_PREFERRED_VERSION: ${DURINDOOR_PG_PREFERRED_VERSION:-18}
Expand Down
19 changes: 0 additions & 19 deletions docs/contributing/meta.json

This file was deleted.

Loading
Loading