Skip to content
API Blog

Sync agents from GitHub

lobu apply is the apply primitive — it diffs a local lobu.toml + agent dirs against a Lobu Cloud org and converges the org to match. Any CI runner can call it, and GitHub Actions is the path of least resistance: push to main triggers an apply, PRs preview a dry-run diff in the check output.

There is no Lobu-side sync feature. The repo is the source of truth and CI is the cron. That keeps Lobu opinion-free about how you structure branches, reviews, multi-env promotion, secret stores — those are choices you already made for the rest of your stack.

  1. A git repo with a lobu.toml at the root (or in a subdirectory).
  2. A LOBU_TOKEN secret in the repo (Settings → Secrets and variables → Actions). Mint one with lobu token create from a logged-in shell (it defaults to the mcp:read mcp:write scope, which lobu apply uses).
  3. Any provider keys your agents reference (ANTHROPIC_API_KEY, etc.) added as repo secrets too — lobu apply reads them via $VAR interpolation in lobu.toml.
.github/workflows/lobu-apply.yml
name: Sync agents
on:
push:
branches: [main]
pull_request:
permissions:
contents: read
concurrency:
group: lobu-apply-${{ github.ref }}
cancel-in-progress: false
jobs:
apply:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.5
- name: Apply
env:
# CLI reads LOBU_API_TOKEN as the env-var override for stored credentials.
LOBU_API_TOKEN: ${{ secrets.LOBU_TOKEN }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
bunx --bun @lobu/cli apply --dry-run
else
bunx --bun @lobu/cli apply --yes
fi

--dry-run on PRs gives reviewers the full add/update/delete plan in the check log. --yes on push to main actually converges the org.

my-agents/
├── lobu.toml
├── agents/
│ ├── support-bot/
│ │ ├── IDENTITY.md
│ │ ├── SOUL.md
│ │ └── USER.md
│ └── ops-bot/
│ └── ...
└── .github/workflows/lobu-apply.yml

lobu.toml references each agent’s directory:

[agents.support-bot]
name = "support-bot"
description = "Customer support triage"
dir = "./agents/support-bot"
[[agents.support-bot.providers]]
id = "anthropic"
model = "claude/sonnet-4-5"
key = "$ANTHROPIC_API_KEY"

See lobu apply for the full file format and the list of fields that get synced.

For staging and prod orgs, run two jobs (or two workflows) with different --org flags and different LOBU_TOKENs:

- name: Apply to staging
env:
LOBU_API_TOKEN: ${{ secrets.LOBU_TOKEN_STAGING }}
run: bunx --bun @lobu/cli apply --org my-org-staging --yes
- name: Apply to prod
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
env:
LOBU_API_TOKEN: ${{ secrets.LOBU_TOKEN_PROD }}
run: bunx --bun @lobu/cli apply --org my-org-prod --yes

Stage on push-to-main, prod on tag, prod-on-approval — all standard Actions patterns; nothing Lobu-specific.

  • It will not edit secrets in your provider accounts. $VAR references are resolved at apply time from the runner’s environment; the values never leave the runner.
  • It will not import existing cloud-side agents into your repo. If you’ve been editing in the admin UI and want to flip to git-managed, hand-write lobu.toml against the current state. (A lobu pull to scaffold this automatically is not yet implemented.)
  • It will not silently overwrite manual UI edits without showing the diff. Every apply prints the plan; --dry-run lets you preview without converging.

Since the agents flatten landed, definition fields (system prompts, model picker, skills, packages) require admin scope to edit via the API. If your repo is the source of truth, restrict admin access on the org so the only writers are CI tokens and the diff is meaningful.