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:

  1. 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.
  2. Web app → local. The orchestrator writes a file via write_file. Hubify commits the change to GitHub on your behalf. You git pull and 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

FieldValue
Payload URLhttps://hubify.com/api/webhooks/github
Content typeapplication/json
Secret(paste from step 1)
EventsJust 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.md and 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.

← Back to docs index