Skip to content

Document the Conductor API and the dbosctl CLI - #605

Merged
devhawk merged 16 commits into
mainfrom
conductor-api-and-dbosctl
Aug 17, 2026
Merged

Document the Conductor API and the dbosctl CLI#605
devhawk merged 16 commits into
mainfrom
conductor-api-and-dbosctl

Conversation

@devhawk

@devhawk devhawk commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Conductor's HTTP API and the dbosctl CLI had no documentation. This adds two pages under Deploy To Production and links them from the Conductor overview.

Both are new files, so the diff is additive — nothing existing is rewritten beyond one bullet on conductor.md.

The pages

Conductor API — base URLs, the three ways to get the OpenAPI spec, authentication, resource scoping, the RFC 9457 error model, listing and filtering conventions, a map of all 64 operations by area, the operations a no-auth self-hosted deployment does not register, and how to generate a client.

dbosctl CLI Reference — installation, profiles, authentication, configuration precedence, output formats, exit codes, and a command-by-command reference. Follows the shape of the existing Cloud CLI reference page.

The sidebar is autogenerated from the directory, so no sidebars.js change is needed.

Where the content came from

Not from the READMEs. The endpoint reference, parameter lists, and error shapes were read out of the OpenAPI spec, and the CLI reference was generated from a recursive --help dump of a real build, then diffed back against it mechanically — 38 leaf commands, no undocumented commands, no invented flags.

Details that came from reading the implementation rather than the spec text, because a reader would otherwise hit them as surprises:

  • Workflow mutations need a live executor. Cancel, resume, restart, fork, and delete are dispatched to a healthy connected executor rather than applied in Conductor's database, so they fail outright when nothing is running — resume and restart additionally need an executor on the latest version.
  • The autoscaling operations require a DBOS Teams plan and return 403 otherwise.
  • Getting the spec from the Conductor image needs --entrypoint. The image's entrypoint waits for Postgres and runs migrations without forwarding arguments, so the obvious docker run <image> openapi hangs waiting for a database the subcommand does not need.

Two scoping calls worth a look

The API is not "everything the console does." An earlier draft said so; it is wrong, because the console also drives DBOS Cloud — deploying applications, provisioning databases, billing — none of which this API touches. Both pages now scope it to the Conductor control plane, which is what the console shows for a Conductor-connected application whether it runs on your own infrastructure or on DBOS Cloud, and point the cloud-specific operations at the pages that own them.

Nothing is framed as versioned. There is one public API; the predecessor is internal. v2 appears only in URLs and paths, where you actually type it, and never in prose as though it were a choice.

Verified against the shipped API

The pages track conductor main as of the applicationName revert (dbos-inc/dbos-conductor#187) and the CLI as of dbos-inc/dbos-ctl#8 and #9:

  • the listWorkflows query parameters and the full workflow-search body field list match the spec exactly;
  • all 64 operations appear in the endpoint tables, and all 16 OAuth-gated operations are named by operation ID;
  • applicationName is documented as a response field only — the request filters were removed by Better Python Styling #187;
  • install instructions follow the dbos-clidbos-ctl repository rename and lead with the new install script.

The site builds. The only broken-anchor warnings are pre-existing ones on the Go reference pages, untouched by this branch.

One sequencing note

The dbosctl page links to the CLI's releases page and its raw.githubusercontent.com install script, both of which are only reachable once that repository is public and a release is tagged. The page carries an early-access admonition, so it is not misleading in the meantime, but this probably wants to land alongside that flip.

🤖 Generated with Claude Code

devhawk and others added 9 commits August 12, 2026 12:53
Conductor's v2 API is now deployed in DBOS Cloud and describes itself with
a generated OpenAPI 3.1 spec, and dbosctl is the command-line client built
on it. Neither had documentation.

Adds two pages under "Deploy To Production":

- Conductor API: where to get the spec (cloud, self-hosted, or the
  conductor binary's `openapi` subcommand), authentication, resource
  scoping, the RFC 9457 error model, listing and filtering conventions, a
  map of the endpoint surface by area, the operations a no-auth self-hosted
  deployment does not register, and how to generate a client.

- dbosctl CLI Reference: installation, profiles, authentication,
  configuration precedence, output formats, exit codes, and a
  command-by-command reference, following the shape of the existing Cloud
  CLI reference page.

Also links both from the Conductor overview page.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Conductor un-gated listPermissions; the grantable-permission catalog is a
static allow-list, fetchable in every mode.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two corrections against the shipped API:

The applicationName filter is gone (conductor #187), so the tip describing
it was documenting an input that no longer exists. What survives is the
response side: workflows, queues, and schedules each report the application
that owns them, which is how you tell whose objects you are looking at when
several applications share a system database. Listing is always scoped to
the application in the path, and there is deliberately no way to read a
co-tenant's objects through it -- address that application directly.

The four autoscaling operations require a DBOS Teams plan and return 403
otherwise, which the page did not say. Also notes that both GETs 404 with no
policy installed, and mentions KEDA alongside the other scalers since that
is what conductor's own design targets.

Names the three domain-claim operations in the no-auth list rather than
referring to them collectively, so all sixteen OAuth-gated operations are
greppable by operation ID.

Verified against the spec: the listWorkflows query parameters and the search
body fields both still match, no operations were added or removed, and the
CLI command surface is unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There is one public API. Calling out that "the API is versioned" and that
this page documents v2 invites a reader to wonder which version they want
and whether a v1 is available to them -- neither of which is a question they
have. The predecessor is internal.

The v2 in URLs stays, since that is what you actually type, but nothing in
the prose treats it as a choice.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The CLI now shows which application owns a workflow, queue, or schedule.
The API page explains the concept, but a reader in the CLI reference would
never cross over, and this is the only way to tell whose objects you are
looking at when applications share a system database.

Put in Output rather than in the three command entries: this page documents
commands and flags, not output fields, and singling out one field in three
places would read as though the rest were exhaustive.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
"Everything you can do from the console you can also do over this API" was
wrong in both directions that matter. The console also drives DBOS Cloud --
deploying applications, provisioning databases, secrets, billing -- none of
which this API touches. A reader taking the claim literally would go looking
for deployment endpoints that do not exist.

Reframes it around what the API actually is: the Conductor control plane,
which is what the console shows for a Conductor-connected application
whether it runs on your own infrastructure or on DBOS Cloud. Points the
cloud-specific operations at the pages that own them.

The same overclaim was in the Conductor overview bullet, which said
everything the dashboard does is available over the API. Now scoped to
workflow, queue, and schedule management.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
We ship the Docker image, not a standalone binary, so `conductor openapi`
was an instruction nobody could follow.

The image needs `--entrypoint ./dbos-conductor` to reach the subcommand:
its entrypoint script waits for Postgres, runs migrations, and execs the
server without forwarding arguments, so `docker run <image> openapi` would
hang waiting for a database it does not need.

Verified against dbosdev/conductor:0.17.0 -- both the 3.1 and the 3.0
downgrade produce the expected spec, and its output is byte-identical to
what conductor main generates today.

Also suggests pinning a version tag over latest when the spec feeds code
generation, so a regenerated client only moves when you decide it does.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Requiring a Go toolchain is a strange prerequisite for a CLI that talks to a
server, and it was the only option this page offered. Releases now ship
archives for Linux, macOS, and Windows on amd64 and arm64.

Drops `make build` from this page: it needs a clone of the repository, which
end-user documentation should not assume. It stays in the repository README
where contributors will find it.

The example filename matches goreleaser's archive naming, so it is the name
a reader will actually see on the releases page.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The CLI repository is now dbos-inc/dbos-ctl, so the releases link and the
`go install` path both pointed at a name that only resolved through a
GitHub redirect.

Leads with the install script rather than a manual download: it picks the
right archive for the platform, and it checks the download against the
release checksums, which a reader unpacking a tarball by hand would not.
Direct download and `go install` stay for people who want them.

Verified that the documented `VERSION=... BIN_DIR=... sh` form actually
passes both through the pipe, under dash as well as bash.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Comment thread docs/production/dbosctl.md Outdated
`dbosctl` is a command-line client for the [Conductor API](./conductor-api.md). It manages workflows, queues, schedules, applications, and API keys against DBOS-managed Conductor or a [self-hosted Conductor](./hosting-conductor.md), with the target selected by a named **profile**.

:::info
The binary is named `dbosctl`, not `dbos`. The DBOS language SDKs ship their own `dbos` entrypoints (the Python SDK, for example, installs a `dbos` console script), so the `ctl` suffix keeps this CLI unambiguous alongside any of them. `dbosctl` is also distinct from [`dbos-cloud`](./dbos-cloud/cloud-cli.md), which manages applications and databases hosted on DBOS Cloud.

@kraftp kraftp Aug 13, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really needed, clear enough from the name of the page

Against a self-hosted Conductor running without authentication:

```shell
dbosctl config set local --url http://localhost:8090

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about self-hosted with auth?

Comment thread docs/production/conductor-api.md Outdated
The mutating workflow operations — cancel, resume, restart, fork, and delete — are carried out by your application, not by Conductor's database. Conductor dispatches them over the websocket to a healthy connected executor. If an application has no healthy executor connected (resume and restart additionally require one running the application's latest version), the call fails rather than being queued for later.
:::

### Queues and autoscaling

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not document this until it's done (I know it's in the OpenAPI spec, but we can keep it out of our public docs)

Comment thread docs/production/conductor-api.md Outdated
Workflow inputs and outputs can be large, so they are omitted unless you ask for them with `loadInput` and `loadOutput`.

:::tip
Several applications can share one system database. When they do, each workflow, queue, and schedule reports the application that owns it in an `applicationName` field, so you can tell whose objects you are looking at. The field is null for objects recorded before DBOS Transact tracked application names, and for in-memory queues.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably remove this, API detail that doesn't deserve so much prominence (and misleading, applicationName is reported whether the system database is shared or not).

Comment thread docs/production/conductor-api.md Outdated
curl -O https://cloud.dbos.dev/conductor/v2/openapi-3.0.json
```

The spec served here is Conductor's own, with only its `servers` entry repointed at `/conductor` so that generated clients resolve paths correctly through DBOS Cloud. Nothing else — no path, schema, or security scheme — is rewritten or filtered.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The spec served here is Conductor's own, with only its `servers` entry repointed at `/conductor` so that generated clients resolve paths correctly through DBOS Cloud. Nothing else — no path, schema, or security scheme — is rewritten or filtered.
The spec served here is Conductor's own, with only its `servers` entry repointed at `/conductor` so that generated clients resolve paths correctly through DBOS Cloud.

Comment thread docs/production/conductor-api.md Outdated
The semantics of cancelling, resuming, and forking are described in [Workflow Management](./workflow-management.md). **Restart** starts a new execution of a workflow, with a new ID and the same inputs, from its first step; the original workflow is left untouched. The bulk variants take an array of workflow IDs and apply the same operation to each, which is far cheaper than issuing the calls one at a time. **Export** and **import** move a workflow and its steps between deployments as a JSON document — useful for reproducing a production failure in a development environment.

:::info
The mutating workflow operations — cancel, resume, restart, fork, and delete — are carried out by your application, not by Conductor's database. Conductor dispatches them over the websocket to a healthy connected executor. If an application has no healthy executor connected (resume and restart additionally require one running the application's latest version), the call fails rather than being queued for later.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The mutating workflow operations — cancel, resume, restart, fork, and delete — are carried out by your application, not by Conductor's database. Conductor dispatches them over the websocket to a healthy connected executor. If an application has no healthy executor connected (resume and restart additionally require one running the application's latest version), the call fails rather than being queued for later.
Workflow operations are carried out by your application, not by Conductor's database. Conductor dispatches them over the websocket to a healthy connected executor. If an application has no healthy executor connected, the call fails.

Comment thread docs/production/conductor-api.md Outdated
https://cloud.dbos.dev/conductor/v2/orgs/my_org/apps/my-app/workflows
```

The paths themselves are identical in both deployments — only the base differs. This is deliberate: a single generated client works against DBOS-managed and self-hosted Conductor with nothing but the base URL changed.

@kraftp kraftp Aug 13, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The paths themselves are identical in both deploymentsonly the base differs. This is deliberate: a single generated client works against DBOS-managed and self-hosted Conductor with nothing but the base URL changed.
The paths themselves are identical in both deployments; only the base differs.

devhawk and others added 7 commits August 14, 2026 09:49
- Apply the three inline suggestions: tighten the base-URL and served-spec
  notes, and simplify the workflow-dispatch admonition.
- Drop the applicationName tip. It gave an API detail too much prominence
  and was misleading: applicationName is reported whether or not the system
  database is shared. Trims the matching aside in the dbosctl reference,
  which linked into it.
- Drop the autoscaling endpoints, their Teams-plan note, and the policy
  explanation. They are in the OpenAPI spec but not finished, so keep them
  out of the public docs for now; the section is just "Queues" again.
- Drop the dbosctl naming admonition — the page title carries it.
- Add a self-hosted-with-OIDC quick start, between the managed and no-auth
  ones; the profile table already covered the shape but nothing showed it.
- Remove the restart endpoint. Conductor deleted it in dbos-inc/conductor#190
  and dbos-ctl#10 dropped the matching command; fork covers the same ground.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The note sat under Workflows and named cancel/resume/fork/delete, implying
dispatch was a property of mutating a workflow. It is not: in
services/conductor, queues, schedules, and the workflow reads (list, get,
steps, events, notifications, streams, export, aggregates) all dispatch to a
healthy executor too, as do listing application versions and setting the
latest. ListWorkflows returns ErrNoHealthyExecutors exactly like
CancelWorkflow does.

Replace it with a "How Operations Are Served" section that splits the API by
what answers the request — Conductor's database (identity, roles, API keys,
application registration and settings, alerting, audit, metrics) versus your
application over the websocket — and notes the 503/502 that only the second
group returns, now also listed among the common statuses.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The profile table listed the managed shape as OIDC-issued user JWT only,
implying dbos_ API keys were a self-hosted concession. They are not:
APIKeyAuthenticationMiddleware keys off the dbos_ prefix on the bearer token
and is wired in wherever OAuth is on, so both authenticated shapes accept
either credential. Managed and self-hosted-with-OIDC differ in where the OIDC
settings come from, not in what they authenticate.

Also correct the identity column, which claimed "your real user" for both:
an API key caller has no user identity, which is why whoami needs a login and
why an API-key profile needs an explicit --org.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Dispatch is not a property of mutating a workflow: every workflow command,
reads included, goes to a healthy executor, which the Conductor API page now
covers once. Point there instead of restating it per command.

What is command-specific is the version constraint, and it is narrower than
the note claimed. Only ResumeWorkflow and BulkResumeWorkflow filter executors
to the latest application version; cancel, delete, fork, fork-from-failure,
import/export, and every read take any healthy executor. So resume is the one
worth calling out, and the caller-visible consequence is that a connected
application mid-rollout can resume nothing while everything else works.

Also drop the `workflow restart` reference section, missed when the command
came out in dbos-ctl#10.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Scoping the note to workflow commands still implied they were special. They
are not: queue and schedule commands dispatch identically, as do app versions
and app set-version (ListApplicationVersions, SetLatestApplicationVersion),
while the rest of app plus api-key, permission, and the auth and config
commands are answered by Conductor itself.

Since the split cuts across the reference sections, hoist it above them as its
own table rather than repeating a variant per section, and leave the workflow
section with only what is genuinely local to it, the resume version constraint.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@devhawk
devhawk merged commit 756419e into main Aug 17, 2026
1 check passed
@devhawk
devhawk deleted the conductor-api-and-dbosctl branch August 17, 2026 22:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants