Ship a Claude Agent to Your Team
You built a great Claude agent locally — a system prompt, a few tools, maybe a
.claude/agents/*.md. It works on your laptop. But your teammates can't use it,
there's no governance, no shared traces, and no way to run it as a specific
end-user with their own keys.
This tutorial publishes that local agent to Waxell as a declarative
claude_agent_sdk agent. When you're done it runs on the governed
isolation-runner, lives at https://<your-tenant>.waxell.dev/agents/<name>, and
can resolve per-end-user credentials host-side — so the model never sees a
raw secret.
Run wax claude-init once in your project. It installs the
ship-claude-agent-to-waxell skill, so Claude Code can drive this whole
tutorial for you — just say "deploy this agent to Waxell."
Prerequisites
pip install waxell # ships the `wax` CLI
wax login # or configure a profile (see below)
wax whoami # ALWAYS verify tenant + identity first
Pushing to prod uses a profile that points at your prod tenant, e.g.
wax -p acme_prod …. Verify with wax whoami -p acme_prod. Don't assume the
default profile is prod.
1. Describe the agent in waxell.yaml
A claude_agent_sdk agent on Waxell is declarative. Translate your local agent
into a waxell.yaml at the root of your project:
version: 1
defaults:
framework: claude_agent_sdk
owner: you@acme.com
agents:
- name: release_notes
version: 1.0.0 # bump on every re-push
display_name: Release Notes Writer
description: Drafts release notes from a changelog.
model: claude-3-5-sonnet
tools: [Read, Glob, Grep, WebFetch]
system_prompt: |
You write crisp, user-facing release notes from a raw changelog.
Group changes by theme, lead with user impact, skip internal churn.
signals:
- name: write_release_notes
source_type: webhook
description: Draft release notes for a version.
schema:
prompt:
type: string
description: The changelog + version to summarise
max_turns: 12
max_budget_usd: 4.0
toolsare the Claude Code built-ins (Read,Write,Edit,Bash,Glob,Grep,WebSearch,WebFetch, …). List only what the agent needs.signalsare how the agent is triggered; theschemais its input.- Paste your local system prompt in directly.
2. Validate and publish
wax -p acme_prod push --dry-run # validate the manifest
wax -p acme_prod push --include-source # publish (source travels with it)
wax -p acme_prod agents info release_notes
That's it — the agent is live at
https://acme.waxell.dev/agents/release_notes. Your team can see its spec,
bindings, traces, cost, and governance.
3. Run it
wax -p acme_prod signals send write_release_notes \
--data '{"prompt":"v2.1: added SSO, fixed 3 billing bugs..."}'
wax -p acme_prod runs list --agent release_notes
wax -p acme_prod runs show <run_id>
The run's Setup span shows exactly what the agent was provisioned with — allowed tools, domains, identity. That's your first stop when debugging.
4. Make it per-user (optional)
The payoff of running on Waxell instead of a laptop: the same agent can run as a specific end-user, reasoning on their LLM key and calling tools with their tokens — all resolved host-side.
a) Register the end-user (maps your app's user id to a Waxell sub-user):
wax -p acme_prod end-users create --tenant-sub-user-id alice \
--email alice@acme.com --display-name "Alice"
b) Set that user's secrets (their own Anthropic key, a tool token). These are write-only and encrypted at rest — you set/rotate but never read them back:
wax -p acme_prod end-users set-secret alice ANTHROPIC_API_KEY sk-ant-…
wax -p acme_prod end-users set-secret alice GITHUB_TOKEN ghp_…
wax -p acme_prod end-users list-secrets alice # keys only, never values
c) Run as Alice — your backend stamps a signed _sub_user_identity on the
signal (stamp both sub_user_id and user_id):
POST /api/v1/signals/write_release_notes/
{
"prompt": "...",
"_sub_user_identity": {"sub_user_id": "alice", "user_id": "alice", "email": "alice@acme.com"}
}
The run now reasons on Alice's key and uses Alice's tokens. Resolution precedence is SubUser → Tool → Agent → Tenant — a user's own credential overrides every shared default, and one user can never resolve another's.
Gotchas
- Bump
version:on every re-push — re-pushing the same version with changed content fails withsemver_conflict. - Don't hardcode tool names in the prompt; the platform may expose a tool as
mcp__…__<name>. Say "use the available GitHub tool." wax whoamifirst, always — the #1 cause of "it deployed to the wrong place" is the wrong profile.
What's next
- Build & push a custom tool — give the agent a capability the built-ins don't cover.
- Add a per-user tool integration (a "connect your GitHub" domain) so the agent acts on third-party APIs as the end-user.
- Wire governance policies to the agent (see the Governance tutorial).
- Explore the Token Lab in the workspace — a live reference for the whole per-end-user credential flow.