CLI Recipes
Short, copy-pasteable patterns for the things people actually do with savine.
Deploy on every push to main
yaml
# .github/workflows/deploy-agent.yml
name: Deploy Savine Agent
on:
push:
branches: [main]
paths: ['agents/**']
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20 }
- run: npm install -g savine
- run: savine deploy ./agents/researcher
env:
SAVINE_API_KEY: ${{ secrets.SAVINE_API_KEY }}Add a smoke test step before the deploy goes out:
yaml
- run: |
AGENT_ID=$(jq -r .id ./agents/researcher/.savine.json)
savine run --agent "$AGENT_ID" --input "ping" --follow
env:
SAVINE_API_KEY: ${{ secrets.SAVINE_API_KEY }}Preview deploys per-branch
bash
#!/usr/bin/env bash
set -euo pipefail
SLUG=$(git rev-parse --abbrev-ref HEAD | tr '/A-Z' '-a-z')
# temporarily override the agent name so previews don't collide with prod
sed -i.bak "s/^name:.*/name: preview-${SLUG}/" config.yaml
savine deploy
mv config.yaml.bak config.yamlStream logs to a file
bash
savine logs --follow | tee -a savine-$(date +%Y%m%d).logWait for a task to finish in a script
bash
TASK_ID=$(savine run -a "$AGENT" -i "$PROMPT" | awk '/Task submitted:/ {print $NF}')
# poll until done
while true; do
STATUS=$(savine tasks get "$TASK_ID" | awk '/^ status/ {print $2; exit}')
case "$STATUS" in
COMPLETED) echo ok; break ;;
FAILED|CANCELLED) echo "$STATUS"; exit 1 ;;
esac
sleep 2
doneOr just use --follow:
bash
savine run -a "$AGENT" -i "$PROMPT" --followRotate an API key
bash
# issue a new key in the dashboard or via the API, then:
savine config apiKey ac_new_key_…
savine whoami # confirmSwap between environments (prod / staging / self-hosted)
bash
# save a staging profile
cat > ~/.savine/staging.json <<EOF
{ "apiUrl": "https://staging.savine.in", "apiKey": "ac_staging_…" }
EOF
# alias to switch
alias savine-prod='SAVINE_CONFIG=$HOME/.savine/config.json savine'
alias savine-staging='SAVINE_CONFIG=$HOME/.savine/staging.json savine'Or use SAVINE_API_URL + SAVINE_API_KEY inline:
bash
SAVINE_API_URL=https://staging.savine.in \
SAVINE_API_KEY=ac_staging_… \
savine agents lsImport a GitHub repo as a system
bash
savine systems from-github https://github.com/acme/research-agent --branch mainThe platform clones the repo, resolves the system manifest, and deploys every agent in the graph.
Wipe a dev agent at the end of a test run
bash
trap 'savine agents rm "$AGENT_ID" -y' EXIT
savine deploy
AGENT_ID=$(jq -r .id .savine.json)
# …tests…Seed an agent's memory
bash
savine memory add "$AGENT_ID" "The company's HQ is in Bengaluru." --type fact
savine memory add "$AGENT_ID" "Prefer concise, bulleted answers." --type preference
savine memory stats "$AGENT_ID"Find the slowest tool calls
bash
savine metrics tools | sort -k3 -rn | headBulk-cancel running tasks
bash
savine tasks ls --status RUNNING -n 100 \
| awk 'NR>2 {print $5}' \
| xargs -I{} savine tasks cancel {}Debugging a failed task
savine tasks get <id>— read the full trace.- Look at the last
TOOL_CALL/TOOL_RESULT/ERRORstep. - Re-run just that step's input locally with the Python SDK's
savine-sdk run agent.py --input …. - Fix,
savine deploy,savine run --follow.
Pipe structured output into jq
Pass --json to any command that returns structured data and the CLI emits raw JSON instead of a formatted table.
bash
savine --json agents ls | jq -r '.[] | "\(.name)\t\(.id)"'
savine --json tasks ls -n 50 | jq '[.[] | select(.status=="FAILED")] | length'
savine --json tasks get $TASK | jq -r .result.answer
savine --json whoami | jq -r .user.apiKeySupported on whoami, agents ls/info, systems ls/info, workflows ls/info, tasks ls/get. More surface on the roadmap.