Local Agents (Claude Code, Codex, gh)
Run any local AI coding agent against your Hubify lab. Edits sync both ways through GitHub.
Local Agents
Hubify is built around the orchestrator chat in the web app, but the lab's source-of-truth lives in GitHub. That means any local AI coding agent — Claude Code, Codex, Cursor, gh CLI, or a plain git workflow — can edit the lab's files and stay in sync with the web app.
There are two flows:
- Local → web app. You edit a file in your editor, commit, push. GitHub fires a webhook, Hubify pulls the new tree, the captain sees the changes in seconds.
- Web app → local. The orchestrator writes a file via
write_file. Hubify commits the change to GitHub on your behalf. Yougit pulland keep working.
Both flows share the same per-lab GitHub repo, so the only state you have to keep in sync is the repo itself.
Prerequisites
- A Hubify lab with a linked GitHub repo (Settings → Lab → Connect GitHub repo)
- A Hubify API key with
lab:<slug>:rw(mint one in Settings → API Keys) - Local clone of the repo:
git clone https://github.com/<owner>/<repo>
One-time setup
Step 1 — Mint a webhook secret
curl -X POST https://hubify.com/api/v1/sync/secret \
-H "Authorization: Bearer hk_live_..." \
-H "Content-Type: application/json" \
-d '{ "labId": "<lab id>" }'
Returns:
{
"secret": "...64 hex chars...",
"existed": false,
"webhookUrl": "https://hubify.com/api/webhooks/github"
}
The secret is shown once. Copy it.
Step 2 — Add the webhook in GitHub
In your repo: Settings → Webhooks → Add webhook
| Field | Value |
|---|---|
| Payload URL | https://hubify.com/api/webhooks/github |
| Content type | application/json |
| Secret | (paste from step 1) |
| Events | Just the push event |
GitHub sends a ping immediately. If you see green, it worked.
Step 3 — Turn on auto-push (optional)
If you want orchestrator file edits to land as commits in the same repo, toggle Settings → Lab → Auto-push orchestrator edits. Without it, orchestrator edits live only in Hubify until you sync them down manually.
Step 4 — First sync
If the repo already had files before you linked it, kick off a one-time pull:
curl -X POST https://hubify.com/api/v1/sync \
-H "Authorization: Bearer hk_live_..." \
-H "Content-Type: application/json" \
-d '{ "labId": "<lab id>" }'
Returns counts: { ok, pulled, updated, skipped, removed, sha }.
Working with Claude Code
Once the webhook is wired up, Claude Code "just works" against the lab repo:
cd ~/code/<your-lab-repo>
claude
Then in the Claude Code session:
Read
experiments/exp-007.mdand propose a tighter prior on the noise floor. Update the file, commit with a clear message.
Claude edits the file, commits, pushes. Hubify pulls within a few seconds. The captain sees the new content in the Files panel and an entry in the activity feed: Synced owner/repo · 0 added, 1 updated, 0 removed (a1b2c3d).
Working with Codex
Same shape — point Codex at the cloned repo and let it edit. Push when done.
cd ~/code/<your-lab-repo>
codex
Working with gh CLI / plain git
You don't need an AI agent at all. Any push to the default branch syncs:
echo "TODO: add ablation study" >> ROADMAP.md
git add ROADMAP.md
git commit -m "roadmap: queue ablation study"
git push
REST API for direct file ops
If you want to script edits without going through git, hit /api/v1/files:
# Read a file
curl "https://hubify.com/api/v1/files?labId=<id>&path=/notes/today.md" \
-H "Authorization: Bearer hk_live_..."
# Write or overwrite
curl -X POST https://hubify.com/api/v1/files \
-H "Authorization: Bearer hk_live_..." \
-H "Content-Type: application/json" \
-d '{
"labId": "<id>",
"path": "/notes/today.md",
"content": "# Today\n\nMeeting notes..."
}'
# Update only (404 if file does not exist)
curl -X PATCH https://hubify.com/api/v1/files \
-H "Authorization: Bearer hk_live_..." \
-H "Content-Type: application/json" \
-d '{ "labId": "<id>", "path": "/notes/today.md", "content": "..." }'
# Delete
curl -X DELETE "https://hubify.com/api/v1/files?labId=<id>&path=/notes/today.md" \
-H "Authorization: Bearer hk_live_..."
When auto-push is on, every write/delete via this API also lands as a commit in the linked repo.
Manual sync after a missed event
If Hubify gets out of sync (rare — usually a webhook delivery failure), force a pull:
curl -X POST https://hubify.com/api/v1/sync \
-H "Authorization: Bearer hk_live_..." \
-H "Content-Type: application/json" \
-d '{ "labId": "<id>" }'
You can also limit the sync to a subtree to save time on big repos:
-d '{ "labId": "<id>", "subPath": "papers" }'
Check sync status
curl "https://hubify.com/api/v1/sync?labId=<id>" \
-H "Authorization: Bearer hk_live_..."
Returns:
{
"repo": "https://github.com/owner/repo",
"defaultBranch": "main",
"lastSyncAt": 1714368000000,
"lastSyncSha": "a1b2c3d...",
"autoPushOnEdit": true
}
What gets synced
- All text files (
.md,.py,.ipynb,.tex,.csv,.json,.ts, etc.) - Up to 1 MB per file
Skipped automatically:
- Binary files (images, PDFs, model weights)
node_modules/,.next/,dist/,build/- Lockfiles (
package-lock.json,yarn.lock,pnpm-lock.yaml) - Anything matching
*.min.js/*.min.css
Hubify never deletes a file that wasn't originally pulled from git, even if the path disappears from the tree. So if the orchestrator created /notes/captains-log.md directly in Hubify and you don't have it locally, it stays.
Troubleshooting
Webhook returns 401. Secret mismatch. Re-mint with /api/v1/sync/secret and paste the new value into GitHub.
Webhook returns 412. Lab has no webhook secret yet. Run /api/v1/sync/secret first.
Sync ran but no files appeared. Check the activity feed for the sync log. If it says 0 added, 0 updated, your push targeted a non-default branch — Hubify only syncs the default branch (main for most repos).
Orchestrator edits aren't reaching GitHub. Verify auto-push is on in Lab Settings, and that the linked GitHub user still has write access to the repo.