> ## Documentation Index
> Fetch the complete documentation index at: https://hubify.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 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

```bash theme={null}
curl -X POST https://www.hubify.com/api/v1/sync/secret \
  -H "Authorization: Bearer hk_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "labId": "<lab id>" }'
```

Returns:

```json theme={null}
{
  "secret": "...64 hex chars...",
  "existed": false,
  "webhookUrl": "https://www.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://www.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:

```bash theme={null}
curl -X POST https://www.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:

```bash theme={null}
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.

```bash theme={null}
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:

```bash theme={null}
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`:

```bash theme={null}
# Read a file
curl "https://www.hubify.com/api/v1/files?labId=<id>&path=/notes/today.md" \
  -H "Authorization: Bearer hk_live_..."

# Write or overwrite
curl -X POST https://www.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://www.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://www.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:

```bash theme={null}
curl -X POST https://www.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:

```bash theme={null}
-d '{ "labId": "<id>", "subPath": "papers" }'
```

## Check sync status

```bash theme={null}
curl "https://www.hubify.com/api/v1/sync?labId=<id>" \
  -H "Authorization: Bearer hk_live_..."
```

Returns:

```json theme={null}
{
  "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.
