CtrlK
BlogDocsLog inGet started
Tessl Logo

conductor

Working with Conductor (conductor.build), the parallel-agent app. Creating local and cloud workspaces, the conductor CLI and public API, auth, sessions and messages, deep links, settings and setup scripts, environment variables, and writing briefs for handed-off agents. Use when asked to open, create, rename, archive, or inspect a workspace or session, spin up parallel agents, kick off or hand off work in Conductor, query conductor sql, debug a deep link that did not work, fix Conductor auth, or explain the local-versus-cloud distinction.

76

Quality

94%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

SKILL.md
Quality
Evals
Security

Conductor

The one fact that decides everything

Local workspaces are created with a conductor:// deep link. Cloud workspaces are created with the CLI or the API. The CLI cannot create a local workspace; do not go looking for a subcommand.

They wantDo this
A local workspace (the normal case, Mac)open "conductor://prompt=<urlencoded>&path=<urlencoded repo root>"
A cloud workspace, explicitly (runs on Linux)conductor workspaces create, after checking the caveats below

Creating a local workspace

Write the brief to a file, then build the URL — do not try to inline a multi-line brief into a shell string.

python3 -c "
import urllib.parse
p = open('/tmp/brief.txt').read()
print('conductor://prompt=' + urllib.parse.quote(p, safe='')
      + '&path=' + urllib.parse.quote('/path/to/repo/root', safe=''))
" > /tmp/ws.url

open "$(cat /tmp/ws.url)"

safe='' matters: the default quote leaves / unescaped, which is fine for path but wrong inside prompt. (printf %s "$BRIEF" | jq -sRr @uri produces equivalent output if you prefer jq, though the Python form above is the one verified end to end.)

Percent-encode both values. An unencoded &, #, ? or + in the brief silently truncates the URL — this is the single most common cause of "the deep link doesn't work". Briefs of ~4-6 KB encoded work fine; that is roughly a full page of markdown.

path is the repo root, exactly, no trailing slash. It must be the root of the git repo Conductor has registered, not a subdirectory and not an existing worktree.

What happens: the app creates a git worktree immediately, derives a branch name from the prompt text, and runs scripts.setup. Verified 2026-08-16: 13 workspaces created this way in one session, all present in git worktree list with branch names matching their brief subjects.

The prompt is only PRE-FILLED in the composer. A human must press enter. The session sits idle with zero session_messages rows until they do (confirmed by DB inspection after setup completed). There is no way to make a local deep link auto-run. Say this when you hand the workspace over, or the user will assume the agent is already working.

Other flat forms: conductor://linear_id=<id>&prompt=..., and conductor://async?repo=<name>&plan=<base64 md> which stages [ASYNC]-plan.md into .context/attachments/ (also does not auto-run). Flat variants take key=value&key=value straight after conductor:// with no hostname; only async uses a real hostname. Docs: https://www.conductor.build/docs/reference/deep-links

open exit status proves nothing

open "conductor://..." exits 0 whenever macOS finds a handler registered for the scheme. A malformed URL, an unknown key, or a nonexistent path all still exit 0.

Never report success from the open exit code. Verify with git worktree list in the repo root, or look at the app. If you tell a user you created something on the strength of a 0 exit, you may be wrong and have no way to know.

When the deep link appears not to work

In order: is the app running; is path the exact repo root with no trailing slash; is the URL actually percent-encoded; does a worktree appear in git worktree list. If the worktree exists and the agent simply is not doing anything, that is the pre-fill behaviour above, not a failure.

Locating the CLI (there is a name collision)

/usr/local/bin/conductor is often not Conductor.build. It is commonly the Orkes / Netflix Conductor workflow-orchestration CLI, which has completely unrelated subcommands (workflow, task, worker, agent). Check before use.

The real one:

/Applications/Conductor.app/Contents/Resources/bin/conductor

That is a sh wrapper around .internal/conductor-runtime cli. Verify with conductor --help: the Conductor.build CLI lists auth, projects, workspaces, sessions, messages, models, sql.

The app binary and the runtime contain no literal conductor:// strings, so do not bother reverse-engineering deep links out of them. That was a dead end.

Know where you are running

CONDUCTOR_IS_LOCAL      1 = user's Mac, 0 = cloud Linux sandbox
CONDUCTOR_WORKSPACE_NAME
CONDUCTOR_WORKSPACE_ID  the CLI uses this when a workspace arg is omitted
CONDUCTOR_WORKSPACE_PATH
CONDUCTOR_ROOT_PATH     repo root; equals workspace path in cloud
CONDUCTOR_DEFAULT_BRANCH  local only
CONDUCTOR_PORT          local only, first of ten allocated ports

Auth

Cloud commands need a token in the macOS Keychain.

conductor auth status     # does an entry exist (does not print it)
conductor auth whoami     # verify against the API
conductor auth login --token <token>

! No keychain entry for https://api.conductor.build. means unauthenticated. Do not ask the user to paste a token to you. Tell them to run conductor auth login themselves.

API directly: base https://api.conductor.build/v0, Authorization: Bearer <api key>, spec at https://api.conductor.build/v0/openapi.json.

Creating a cloud workspace

conductor workspaces create \
  [--project-id <id>] [--repo-url <url>] [--branch <name>] \
  [--name <name>] [--session-name <name>] \
  [--agent claude|codex|cursor|acp] [--model <model>] [--effort <level>] \
  [--env KEY=value]... [--channel prod|beta]

Creates the workspace and its first session. To add more sessions later:

conductor sessions create --workspace <id> --agent claude --message "<prompt>" [--fast-mode]
conductor messages create --session <id> --message "<text>"

Check conductor models for each agent's valid model ids and effort levels before assuming a model is unavailable.

Cloud caveats to check first

  1. Cloud is Linux. If the repo's scripts.setup is Mac-specific it will partially fail. Read <repo>/.conductor/settings.toml (or a legacy conductor.json) before recommending cloud. Real example: a setup script that does cp "$CONDUCTOR_ROOT_PATH/.env" .env and links a Herd/Valet site is local-only, and CONDUCTOR_ROOT_PATH is the workspace itself in cloud, so that copy is a no-op at best.
  2. Cloud setup reads settings from the branch the workspace is created from, unlike the Mac app which reads shared settings from the default branch on the remote.
  3. CONDUCTOR_PORT is unset in cloud, so run scripts that need it must be available_in = [ "local" ].

Deep links returned by the API (cloud)

Workspace and session objects carry a deepLink field (a plain string in the OpenAPI spec: no pattern, no example, no documented format). It appears on the workspace and session schemas returned by create/get/list.

For cloud objects, read deepLink from the response rather than constructing one — it encodes ids you would otherwise have to assemble, and the app-opening grammar for an existing remote workspace is not the same as the documented flat local form.

This does not mean deep links can never be written by hand. The flat conductor://prompt=...&path=... form for creating a local workspace is documented and verified working — see "Creating a local workspace" above. The two are different jobs: one opens an object that already exists in the cloud, the other creates a worktree on this Mac.

--channel <prod|beta> selects which desktop-app build the returned deep link should open. It is a query param on every link-returning endpoint:

GET  /v0/projects/{projectId}/workspaces      POST /v0/workspaces
GET  /v0/workspaces/{workspaceId}             POST /v0/workspaces/{workspaceId}/rename
GET  /v0/workspaces/{workspaceId}/sessions    POST /v0/sessions
GET  /v0/sessions/{sessionId}                 POST /v0/sessions/{sessionId}/rename
POST /v0/sessions/{sessionId}/messages

The CLI's own guidance: "Use deep links instead of IDs to direct users to work you've started; deep links are clickable, while IDs are not." So when you do create cloud work, surface the deepLink, not the id.

Other CLI commands worth knowing

conductor workspaces get|rename|archive|sessions|status [workspaceId]
conductor sessions get|rename|archive|messages|status|cancel <sessionId>
conductor sessions messages <id> --after <messageId>   # incremental polling
conductor projects list|get|workspaces
conductor sql "<read-only SELECT>"                     # over session_transcripts_view
  • Add --json for machine-readable output (auth commands are human-readable only).
  • List commands paginate with a small default page. Pass --limit (max 100) and step --offset while the JSON response reports hasMore. Do not assume page one is everything.
  • To find a specific workspace or session, prefer conductor sql over paging list commands. conductor sql --help documents the view's columns. Workspaces with no transcripts yet do not appear in that view, so on zero matches fall back to workspaces/projects list commands before concluding something does not exist.
  • Exit codes: 0 success, 1 runtime, 2 usage, 3 auth, 4 server.
  • Prefer internal subagents for read-only work. Spend a Conductor workspace or session only when the user asks, or when a specific agent or model is only reachable through Conductor.

Writing the brief

The brief is the deliverable, whether you pass it via prompt= in a deep link or paste it for the user. Since the prompt only pre-fills, a bad brief costs the user a full agent run to discover.

  1. Write one self-contained brief per workspace. Independent fixes get separate workspaces; that is the whole point of Conductor. Do not batch unrelated fixes into one prompt.
  2. Include the trap you already found. A brief is worth writing mostly because you can encode the thing that would break a naive fix. Verify the fix is safe before writing the brief, not after. Example: guarding a route on environment('local') looks obviously right and silently breaks every test that hits the route, because APP_ENV=testing; the brief must say ['local', 'testing'] and name the affected test files.
  3. State the scope guard. What not to touch, and which tempting adjacent refactor belongs in a different PR.
  4. Mind where the brief lives. .context/ is per-workspace and gitignored, so a brief written there does not travel to a new workspace. Either paste the brief as the first message, or write it under $CONDUCTOR_ROOT_PATH (the repo root, stable and readable from any workspace). Conductor's "files to copy" defaults to .env* only.
  5. Suggest workspace names, and give the base branch.

Settings and scripts

Precedence: managed > repo local > repo shared > user > defaults. TOML outranks legacy JSON at every layer.

<repo>/.conductor/settings.local.toml    machine-local, one repo
<repo>/.conductor/settings.toml          shared with the team
~/.conductor/settings.toml               this user, all repos
~/.conductor/settings.managed.toml       org-controlled

The Mac client ignores a repo-level conductor.json once .conductor/settings.toml exists, but cloud setup still falls back to conductor.json for a setup script. If a repo has both, that is a migration bug worth flagging. Migration map: scripts.run becomes scripts.run.<id>.command, runScriptMode becomes scripts.run_mode.

Scripts run in non-interactive shells (zsh on Mac, bash in cloud), so put toolchain setup in the script rather than relying on shell startup files.

Docs

There is no /docs/reference/cli page (404 as of CLI 0.80.1). The CLI's own conductor --help command reference is more complete than the site.

Repository
freekmurze/dotfiles
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.