Your first agent
You describe an agent in one sentence. The onboarding agent designs it, test-calls your model key, creates it and streams its first run. Every step advances only after a real 2xx or a terminal status, so you end with output from your own agent, not a mock. An agent is an AI worker with a name and instructions; a run is one execution, input in and output out.
1. State the goal
A sentence about what the agent should do is enough to start.
- You
- Control plane
- Sandbox
- Data stores
To look around with no key, use Try it: the demo.
Before you start
Section titled “Before you start”- A running stack:
pal dev(Develop locally). - An OpenAI or Anthropic key. You can add it during onboarding.
- For the terminal path, the
palCLI (Install).
What happens, in order
Section titled “What happens, in order”It is a conversation: say what you want in your own words, and the onboarding agent asks follow-ups, picks the next step and does it with real calls.
- Model key. With no key yet, the agent’s first job is to get one: a secure form saves it and makes a real test call. A rejected key stops here with the provider’s actual error. The key never appears in the conversation; one pasted into the chat by mistake is saved, tested and removed before anything is stored.
- Describe the goal, for example “Turn my rough meeting notes into a short summary with action items.”
- Review the design. The agent proposes a name, instructions, a capability model (
auto, never a vendor name) and a first task. Ask for changes in plain words (the name stays), or approve. - Create and run. On your go-ahead it creates the agent (never over an existing agent’s name), reads it back, runs it once and shows the real output, or the real error and what to do about it.
- Next steps. It suggests a channel, a budget or an eval suite.
The agent can only call the tools the current step allows; anything else is refused and said so in the chat. It never reports success a call did not return. If it can’t reach the model, the page switches to the step-by-step setup and says why. Step by step in the header opens it any time with the same saved progress; starters (support desk, PR triage, incident responder, daily digest, data analyst, Telegram assistant), spec editing and the optional sandbox run live there.
In the dashboard
Section titled “In the dashboard”Open http://localhost:3001/onboarding and sign in with the seeded dev account (admin@pal.local / pal). It is a conversation with a progress rail beside it (a one-line summary on a phone).
Progress is stored on the server, so a reload or another browser resumes where you left off. Start over clears it. When a step fails, the page names the cause and offers one fix:
| What you see | Fix it offers |
|---|---|
| No model key configured | Add a model key; the design is retried |
| Provider rejected the key | Replace the key |
| Design came back unusable | Rephrase the goal, or use the basic design |
| An agent with that name exists | Rename the agent |
| Budget or quota blocked the run | Open budgets |
In the terminal
Section titled “In the terminal”pal onboardOn a terminal this is the same conversation as the dashboard: type in your own words; keys go into a hidden prompt, never the chat. --steps keeps the step-by-step wizard (health, sign-in, key test, goal, proposal, create, streamed first run), which also takes over if the agent can’t reach the model. --yes never prompts and fails at the first broken step, which suits CI:
pal onboard --yes \ --provider anthropic --api-key "$ANTHROPIC_API_KEY" \ --description "Summarize support tickets into one-line triage notes"Other pal commands reuse the credentials pal onboard saves. To sign in separately: pal login --email admin@pal.local --password pal.
The same flow over REST
Section titled “The same flow over REST”The conversation itself is POST /v1/onboarding/agent/turn ({product: "runtime"|"pal", message?, event?, results?}); every tool the agent calls is one of the endpoints below, all public and scriptable:
export PAL_TOKEN=$(curl -s -X POST http://localhost:8080/auth/login \ -H "Content-Type: application/json" \ -d '{"email":"admin@pal.local","password":"pal"}' | jq -r .token)H="Authorization: Bearer $PAL_TOKEN"; J="Content-Type: application/json"
# 1. Provider key, then a real test callcurl -s -X POST localhost:8080/v1/settings/llm-providers -H "$H" -H "$J" \ -d '{"provider":"anthropic","apiKey":"sk-ant-..."}'curl -s -X POST localhost:8080/v1/settings/llm-providers/anthropic/test -H "$H"
# 2. Design an agent from a goal (returns name, systemPrompt, firstInput, rationale, steps)curl -s -X POST localhost:8080/v1/agents/generate-spec -H "$H" -H "$J" \ -d '{"description":"Turn meeting notes into action items"}' | tee spec.json
# 3. Create it (the instruction field is systemPrompt)jq '{name, description, systemPrompt}' spec.json | \ curl -s -X POST localhost:8080/v1/agents -H "$H" -H "$J" -d @-
# 4. Run it with the suggested first task, then stream eventsRUN_ID=$(jq --argjson i "$(jq .firstInput spec.json)" -n \ "{agentName: \"$(jq -r .name spec.json)\", input: \$i}" | \ curl -s -X POST localhost:8080/v1/runs -H "$H" -H "$J" -d @- | jq -r .id)curl -N localhost:8080/v1/runs/$RUN_ID/events -H "$H" -H "Accept: text/event-stream"generate-spec returns 400 {"code":"no_provider"} with no key, and 502 (bad_spec or llm_failed) when the model call fails. The event stream closes at succeeded, failed or cancelled; read the final output from GET /v1/runs/{id}. Onboarding progress lives at GET, PUT and DELETE /v1/onboarding.
Next: Develop locally with a save-and-rerun loop.