# Optio runs agents from a five-attribute form, and its example env disables auth

> A self-hosted control plane that runs AI coding agents as sessions you can trigger by cron, webhook, ticket or message, on Kubernetes pods you operate or on a paired laptop, with Claude Code, Codex, Copilot, Gemini, Cursor, OpenCode and OpenClaw as runtimes. Underneath sits a compare-and-swap reconciliation loop, and the example configuration ships with authentication switched off.

**jonwiggins/optio** — Workflow orchestration for AI coding agent swarms, from task to merged PR.

- Repository: https://github.com/jonwiggins/optio
- Website: https://optio.host/
- Stars: 1,055 · Forks: 120
- Language: TypeScript
- License: MIT
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/jonwiggins-optio

## The example environment file ships with authentication disabled

The block to read first in the example environment file is the one labelled Authentication, which sets `OPTIO_AUTH_DISABLED=true` and describes it as disabling auth entirely for local dev. That default sits next to an API bound to every interface:

```env
API_PORT=4000
API_HOST=0.0.0.0
OPTIO_AUTH_DISABLED=true
```

Authentication is otherwise pluggable rather than built in, with separate client ID and secret pairs for GitHub, Google and GitLab, and a generic OIDC block whose comment names Keycloak, Authentik, Authelia, Zitadel, Okta and Auth0 alongside issuer URL, client credentials, display name and scopes. Inbound events carry their own secret: `GITHUB_WEBHOOK_SECRET`, generated the same way as the encryption key and required to match what is configured in GitHub's own webhook settings. Optio Local's event ingress is signed too, using a Slack app signing secret whose request URL is given as `<PUBLIC_URL>/api/webhooks/slack/events`.

## `OPTIO_ENCRYPTION_KEY` is the one value the server refuses to start without

One setting in the same file is marked required and is deliberately left empty: `OPTIO_ENCRYPTION_KEY`, the key for secrets at rest, with a comment suggesting `openssl rand -hex 32` and a second line stating the server refuses to start if the value is empty or set to a known-weak one. That is the only hard startup gate described anywhere in the file. So the configuration you get by copying the example has authentication switched off, an API listening on all interfaces, one mandatory key, and nothing else forcing your hand. The OAuth client secrets and the webhook secret are all commented out, which leaves them optional by default, and `GITHUB_WEBHOOK_SECRET` in particular is blank with no refusal attached to it. The asymmetry is the thing to notice: the key protecting your stored credentials is the one setting that cannot be skipped, while the setting deciding who can log in is the one shipped switched off.

## The compose file starts PostgreSQL and Redis and stops there

The example compose file contains two services and no application. PostgreSQL 16 comes up with database and user both named after the project and the password `optio_dev`, a `pgdata` volume, and port 5432 published to the host. Redis 7 on alpine comes up with port 6379 published, a healthcheck that authenticates nothing, and no volume at all:

```yaml
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
```

Two consequences follow. Anything that can reach the host on those two ports reaches a database whose password is published in this repository and a cache with no authentication, which is a development arrangement rather than something to copy onto a shared network. And because Redis gets no volume while PostgreSQL gets `pgdata`, whatever the cache holds is lost when its container is recreated and the database survives. Elsewhere the environment file defaults `OPTIO_RUNTIME` to kubernetes, expects `DOCKER_HOST` pointing at the socket for the Docker runtime, and pins `OPTIO_AGENT_IMAGE` to `optio-agent:latest` with a pull policy of `Never`, because locally built images are not pulled from a registry.

## The root package is still 0.1.0 while the tags are at v0.7.0

The workspace root declares version 0.1.0 and marks itself private, while the published tags are v0.6.3, v0.6.5 and v0.7.0. Nothing in the root manifest ties those two numbers together, so the version a developer reads in the repository is not the version of the software they can install. The rest of the root shows the size of the thing: a pnpm workspace with the package manager pinned to pnpm@10.11.0, turbo driving `dev`, `build`, `lint`, `typecheck` and the database tasks, husky as the prepare hook, commitlint with the conventional config, and lint-staged running eslint and prettier per file type. Two scripts generate Swift and Kotlin from the shared package, which is the clearest sign that the browser console is only one of three clients. The tree also carries four Dockerfiles, agent, api, optio and web, a helm directory, a k8s directory, and three agent instruction files side by side at the root: AGENTS.md, CLAUDE.md and CODEX.md.

## Twelve transitive packages pinned to exact versions, one allowed to build

The pnpm block pins twelve transitive packages to exact versions through overrides: `@grpc/grpc-js` 1.14.4, `@protobufjs/utf8` 1.1.1, `brace-expansion` twice at 2.0.3 and 5.0.6 for two different ranges, `dompurify` 3.4.10, `esbuild` 0.28.1, `fast-uri` 3.1.2, `ip-address` 10.2.0, `postcss` 8.5.15, `protobufjs` 7.6.4, `uuid` 11.1.1, `ws` 8.21.0 and `yaml` 2.9.0. Several of those are exactly the packages a security review would expect to keep moving, and several are the kind of library that ends up in a web console or a proxy path. Beside them, `onlyBuiltDependencies` lists a single entry, `node-pty`, the only package permitted to run install scripts. Pinning this way is a legitimate answer to a dependency tree that will not resolve, and it has the side effect that upgrading stops being automatic and becomes an edit to this file followed by a lockfile refresh.

## Five attributes and eight statuses describe every kind of work

The design centre is one form with five attributes, and the same five apply to every job. When covers now, a cron schedule, a webhook, a ticket from GitHub Issues, GitLab Issues, Linear, Jira or Notion, a GitHub, Slack or Linear event, or a message from a person or another agent. Where is either an isolated pod in a cluster you operate, with one of your repos checked out or with no repo at all, or a directory on your own machine through Optio Local, as it is or on a new branch that becomes a PR. Who is a bare terminal or one of seven named agent runtimes: Claude Code, OpenAI Codex, GitHub Copilot, Google Gemini, Cursor, OpenCode and OpenClaw. What is a prompt or a saved template with `{{param}}` substitution filled from the trigger payload. Then is exits when done, waits for you, or a persistent agent. Everything lands in a single feed on an eight-step scale, needs you, running, queued, waiting, scheduled, paused, done and failed, and the New work form reads your choices back as a sentence so you can see what will happen before it starts.

## Ticket to merged PR means the agent resumes itself and merges on green

The pipeline the project began with is worth reading closely, because the merge is not a human step. Assign a GitHub Issue, Linear ticket or Jira card and Optio provisions a pod for the repo, runs the agent in a git worktree, opens a PR, watches CI, launches a review agent, resumes the author agent when CI fails or a reviewer requests changes, and squash-merges when everything is green. The review is a separate session with its own prompt, model and even vendor, running as a blocking subtask on PR open or CI pass, for Optio-authored pull requests and external ones alike. Which means the review agent's model and instructions are part of your merge policy whether or not anyone writes that down, and the five attributes have no field for merge authority: it follows from how the session was defined. The same pipeline also assumes the agent can be resumed mid-conversation after a failed build, so the prompt has to survive a context that already contains a rejected attempt.

## Persistent agents get a slug, an inbox and an HTTP API to each other

The long-lived shape is the unusual one. A persistent agent is a named thing with a stable slug, an inbox and a cyclic turn loop, and it wakes on a user message, a message from another agent, a webhook, a cron tick or a ticket event. Agents address each other over an inter-agent HTTP API, which is enough to build a dispatcher with specialists behind it, and three pod lifecycle modes trade latency against cost: always-on, sticky and on-demand. The interactive side has its own mechanism, a layered attention detector that reads Claude Code hooks first, then the terminal bell, then silence, and raises needs you as a favicon, a tab count, a push notification, a lock screen Live Activity or an ongoing Android notification, with up to three sessions split side by side and chat from the browser or the mobile apps. Two worked examples of the persistent shape ship under the examples directory, a forge and a Mars mission control. The document itself ends inside its Why Optio section, one word in.

## Conclusion

Optio is a rare agent orchestration project whose README explains its failure model rather than its feature list, and the reconciliation design, pure decision functions over a frozen snapshot applied under compare-and-swap with periodic resync, is the part worth taking whatever you think of the rest. Two things to settle before it touches a real repository. Authentication is off in the example configuration while the API binds to all interfaces, so decide who logs in and how before the first agent runs against your code. And the automatic squash-merge is part of the documented pipeline, which makes the review agent's prompt and model your merge policy and deserves the same scrutiny as a protected branch rule. The rest is ordinary infrastructure: PostgreSQL 16, Redis 7, pnpm and turbo, four Dockerfiles and a helm directory.

## FAQ

### Does Optio need authentication enabled before it will run?

The example environment file sets `OPTIO_AUTH_DISABLED=true`, with a comment saying it disables auth entirely for local dev, alongside `API_HOST=0.0.0.0` and `API_PORT=4000`. Authentication is otherwise OAuth based, with client ID and secret entries for GitHub, Google and GitLab, plus a generic OIDC block naming Keycloak, Authentik, Authelia, Zitadel, Okta and Auth0. A separate `GITHUB_WEBHOOK_SECRET` validates inbound GitHub webhook signatures.

### What does Optio require before the server starts?

`OPTIO_ENCRYPTION_KEY` is required, and the example file states the server refuses to start if it is empty or set to a known-weak value, suggesting `openssl rand -hex 32` to generate one. The same file carries `DATABASE_URL` and `REDIS_URL`, `OPTIO_RUNTIME` set to kubernetes, and an agent image with a pull policy of `Never` for locally built images.

### Which coding agents can an Optio session run?

The Who attribute accepts a bare terminal or an agent runtime, and the named runtimes are Claude Code, OpenAI Codex, GitHub Copilot, Google Gemini, Cursor, OpenCode and OpenClaw, with the model and provider chosen per session. A code review runs as its own session with a separate prompt, model and vendor.

### Where does an Optio session actually run?

Either in an isolated Optio pod in a cluster you operate, with one of your repos checked out or with no repo at all, or in a directory on your own machine through Optio Local, either on the checkout as it is or on a new branch that becomes a PR. Optio Local uses your local CLI login, so no server secrets leave the cluster.

### What does the Optio docker-compose file set up?

Only PostgreSQL 16 and Redis 7. PostgreSQL uses database and user `optio` with password `optio_dev`, a pgdata volume and port 5432 published. Redis has port 6379 published, a healthcheck that runs redis-cli with no password, and no volume, so what it holds does not survive recreating the container. No application service is defined in that file.

## Sources

- [jonwiggins/optio on GitHub](https://github.com/jonwiggins/optio)
- [License: MIT](https://github.com/jonwiggins/optio/blob/main/LICENSE)
- [Project website](https://optio.host/)
- [README](https://github.com/jonwiggins/optio/blob/main/README.md)
- [Releases](https://github.com/jonwiggins/optio/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/jonwiggins-optio
