Local development
Scaffold, preflight, and bridge a localhost agent wrapper to the hosted platform with the pipelines CLI.
The local workflow has three commands: pipelines odyssey init to scaffold the wrapper, pipelines odyssey doctor to validate it, and pipelines odyssey dev to bridge localhost to the platform through a public tunnel.
Scaffold (pipelines odyssey init)
Generate a runnable wrapper instead of writing one manually:
pipelines odyssey init --framework anthropic --dir my-agentThe --framework option accepts scratch, anthropic, openai-agents, strands, and langchain. The scaffold includes app.py (FastAPI wrapper with register_dispatch_route, lazy model client, and sync handler), register.py (calls agents.create_http_agent), tools_schema.json (served at GET /tools_schema), .env.example, requirements.txt, and a README.md. Re-run with --force to overwrite existing files.
Preflight with pipelines odyssey doctor
Turn every registration gotcha into a local green/red check before a run:
pipelines odyssey doctor --app app:app[PASS] SDK + FastAPI importable
[PASS] App imports (app:app)
[PASS] Wrapper boots + ping 2xx — /dispatch -> 200
[PASS] Auth runs before ping — wrong bearer -> 401
[PASS] tools_schema valid + matches app — 2 tools, in sync
[PASS] Outbound proxy reachable (401 = success) — 401 (proxy reachable)It checks that the app imports (including import-time API key failures), boots and answers the ping probe payload with auth ahead of ping, the outbound proxy is reachable (HTTP 401 is the expected success signal), and verifies that served tools_schema matches tools_schema.json. Pass --agent-id (with PIPELINES_API_KEY) to check platform drift, or --csv path.csv to validate dataset columns, initial_state shape, and failure_rules. The command exits non-zero if any check fails.
Bridge with pipelines odyssey dev
pipelines odyssey dev starts a public tunnel, repoints the agent endpoint_url for the session, and restores the previous value on Ctrl-C.
Prerequisites
-
A tunnel binary on PATH:
Provider Install cloudflared (default) brew install cloudflared ngrok brew install ngrok -
A Pipelines API key configured as PIPELINES_API_KEY. The CLI auto-loads a .env file from the current directory before applying flag defaults, so PIPELINES_API_KEY=pk_live_... in .env is sufficient. Shell environment values take precedence. Use --no-dotenv to disable .env loading.
-
A registered external_http agent. Register once with the not_running placeholder (the form provides a one-click button); the CLI overwrites it on every run.
Usage
With PIPELINES_API_KEY in .env (or the shell), run wrapper and tunnel in one command:
pipelines odyssey dev --agent-id 42 --port 8000 --serve-app app:appThe --serve-app app:app option makes the CLI spawn uvicorn app:app --port 8000 directly. This avoids a second shell and prevents tunnel and server port mismatch, which is a common silent cause of agent_unreachable. Omit --serve-app if you prefer to run uvicorn yourself.
Successful start prints:
Agent my-claude-agent (#42) is live at https://random-words-1234.trycloudflare.com/dispatch. Press Ctrl-C to stop.Flags
| Flag | Default | Notes |
|---|---|---|
| --agent-id | required | Agent row to repoint. |
| --port | 8000 | Local port used by the wrapper. |
| --tunnel | cloudflared | cloudflared or ngrok. |
| --api-key | $PIPELINES_API_KEY | Organization API key. |
| --base-url | $PIPELINES_BASE_URL or https://api.pipelines.tech | Override for self-hosted deployments. |
| --tunnel-debug | off | Stream tunnel subprocess output to stderr. |
| --dispatch-path | /dispatch | Path appended to the tunnel URL. |
| --serve-app | off | MODULE:ATTR (example: app:app). Spawns uvicorn on --port with the tunnel. |
| --no-dotenv | off | Skip auto-loading .env from the current directory. |
| -v / --verbose | off | Enable DEBUG logs to stderr. |
Lifecycle
| Trigger | What happens |
|---|---|
| Ctrl-C (SIGINT) / SIGTERM | Tunnel process is stopped (and the --serve-app uvicorn child, if present); endpoint_url is restored to its pre-CLI value. |
| Tunnel exits unexpectedly | Same as above; CLI exits non-zero. |
| SIGKILL | No cleanup runs; reset endpoint_url manually from the dashboard. |
On clean shutdown the CLI prints:
Reverted agent my-claude-agent (#42) endpoint_url to https://prod.example.com/dispatch.The not_running placeholder
When the agent has no prior endpoint_url, the revert target is:
https://__not_running__.pipelines.tech/dispatchThe hostname intentionally does not resolve, so a stray dispatch while the tunnel is down fails fast with agent_unreachable.
The registration form button, Use pipelines odyssey dev placeholder, on the Endpoint URL field fills this in for you.
Without the CLI (manual smoke test)
uvicorn app:app --port 8080
cloudflared tunnel --url http://localhost:8080 # or `ngrok http 8080`Fire a synthetic dispatch:
curl -sX POST $TUNNEL_URL/dispatch \
-H "Authorization: Bearer $AGENT_TOKEN" \
-H "X-Pipelines-Run-Token: dev-token" \
-H "X-Pipelines-Odyssey-Proxy-Url: http://localhost:9999/proxy" \
-H "Content-Type: application/json" \
-d '{
"task_id": 1, "run_id": 1, "agent_id": 1,
"input": { "user_instruction": "Hello, who are you?" },
"odyssey_proxy_url": "http://localhost:9999/proxy"
}'Expect a 2xx response with final_response. Then paste the tunnel URL into the registration form's Endpoint URL field.