Coregit
Guides

Using with AI Agents

Integrate Coregit into your AI coding agent workflow — from repo creation to commit and clone.

Why Coregit for AI Agents?

Traditional Git requires a filesystem, a git binary, and SSH keys. AI agents running in serverless environments don't have these. Coregit replaces all of that with a REST API:

  • No containers, no git binary, no cold starts
  • Multi-file commits in a single HTTP call
  • Instant rollback via snapshots
  • Standard git clone for the final result

Full Workflow

1. Create a Repository

const res = await fetch('https://api.coregit.dev/v1/repos', {
  method: 'POST',
  headers: {
    'x-api-key': process.env.COREGIT_API_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    slug: 'agent-output',
    visibility: 'private',
  }),
});

const repo = await res.json();
// { id: "repo_abc", slug: "agent-output", ... }

2. Generate Code and Commit

Your agent generates files, then commits them all at once:

const commitRes = await fetch(
  'https://api.coregit.dev/v1/repos/agent-output/commits',
  {
    method: 'POST',
    headers: {
      'x-api-key': process.env.COREGIT_API_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      branch: 'main',
      message: 'feat: implement user authentication',
      changes: [
        {
          path: 'src/auth.ts',
          content: `import { hash, verify } from './crypto';

export async function authenticate(email: string, password: string) {
  const user = await db.users.findByEmail(email);
  if (!user) throw new Error('User not found');
  const valid = await verify(password, user.passwordHash);
  if (!valid) throw new Error('Invalid password');
  return { id: user.id, email: user.email };
}`,
        },
        {
          path: 'src/middleware.ts',
          content: `import { authenticate } from './auth';

export async function authMiddleware(req, res, next) {
  const token = req.headers.authorization?.split(' ')[1];
  if (!token) return res.status(401).json({ error: 'No token' });
  try {
    req.user = await verifyToken(token);
    next();
  } catch {
    res.status(401).json({ error: 'Invalid token' });
  }
}`,
        },
        {
          path: 'src/index.ts',
          content: `import { authMiddleware } from './middleware';

app.use('/api', authMiddleware);
app.listen(3000);`,
        },
      ],
    }),
  }
);

const commit = await commitRes.json();
// { sha: "7f3b...", tree_sha: "a1c2...", parent_sha: "0000..." }

3. Create a Snapshot Before Risky Changes

await fetch('https://api.coregit.dev/v1/repos/agent-output/snapshots', {
  method: 'POST',
  headers: {
    'x-api-key': process.env.COREGIT_API_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    name: 'before-refactor',
    branch: 'main',
  }),
});

4. Roll Back if Something Breaks

await fetch(
  'https://api.coregit.dev/v1/repos/agent-output/snapshots/before-refactor/restore',
  {
    method: 'POST',
    headers: {
      'x-api-key': process.env.COREGIT_API_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ target_branch: 'main' }),
  }
);

5. Clone the Result

The user (or CI) clones with standard Git:

git clone https://myorg:cgk_live_KEY@api.coregit.dev/myorg/agent-output.git

Lazy Edits — Stop Rewriting Whole Files

Once a file exists, rewriting it to change three lines is wasteful: your agent burns 5 000 output tokens to regenerate 4 997 that were already correct. action: "lazy_edit" lets the agent send only the diff in its head, marked with // ... existing code ... placeholders, and Coregit merges it server-side inside the same atomic commit.

await fetch('https://api.coregit.dev/v1/repos/agent-output/commits', {
  method: 'POST',
  headers: {
    'x-api-key': process.env.COREGIT_API_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    branch: 'main',
    message: 'fix: null-check user before session',
    parent_sha: currentHead,
    changes: [
      {
        path: 'src/auth.ts',
        action: 'lazy_edit',
        instruction: 'Add user null check before session creation',
        edit_snippet:
          '// ... existing code ...\n' +
          '  const user = db.find(email);\n' +
          '  if (!user) throw new Error("User not found");\n' +
          '  const session = createSession(user);\n' +
          '// ... existing code ...',
      },
    ],
  }),
});

When to use it — any edit where > 80% of the file is unchanged. For a 1-line fix in a 5 000-token file, you're sending ~100 tokens instead of 5 000 — 50× fewer output tokens from your agent's LLM, which is usually the single biggest cost in an agent loop.

Full reference: Commits → Lazy Edits.

Before you edit a file, your agent usually needs to locate the right spot. Instead of running N shell commands in a sandbox to grep/read/list, hand the question to Coregit:

const res = await fetch(
  'https://api.coregit.dev/v1/repos/agent-output/agentic-search',
  {
    method: 'POST',
    headers: {
      'x-api-key': process.env.COREGIT_API_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      q: 'Where is the JWT verification middleware and what does it check?',
      ref: 'main',
    }),
  }
);
const { answer, locations } = await res.json();
// answer:    "JWT verification lives in src/auth/middleware.ts, line 42..."
// locations: [{ path: "src/auth/middleware.ts", start_line: 42, end_line: 58 }]

Coregit materializes the repo at ref, runs an upstream model through a 3–6 step grep/read/glob loop inside a sandboxed filesystem, and returns an answer + file pointers. Your agent gets one clean fact instead of 30 tool calls.

Set stream: true to receive per-turn SSE events (turn_start, tool_call, tool_result, finish) if you want to show progress.

Full reference: Agentic Search.

Conflict Detection

When multiple agents work on the same repo, use parent_sha to detect conflicts:

// Get current branch head
const branchRes = await fetch(
  'https://api.coregit.dev/v1/repos/agent-output/branches/main',
  { headers: { 'x-api-key': process.env.COREGIT_API_KEY } }
);
const { sha: currentHead } = await branchRes.json();

// Commit with CAS check
const commitRes = await fetch(
  'https://api.coregit.dev/v1/repos/agent-output/commits',
  {
    method: 'POST',
    headers: {
      'x-api-key': process.env.COREGIT_API_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      branch: 'main',
      message: 'update config',
      parent_sha: currentHead, // Will return 409 if branch moved
      changes: [
        { path: 'config.json', content: '{"v": 2}' },
      ],
    }),
  }
);

if (commitRes.status === 409) {
  // Branch was updated by another agent — re-read and retry
}

Branching and Merging

For multi-step tasks, agents can work on feature branches and merge when ready:

// Create a feature branch
await fetch('https://api.coregit.dev/v1/repos/agent-output/branches', {
  method: 'POST',
  headers: {
    'x-api-key': process.env.COREGIT_API_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ name: 'agent-task-42', from: 'main' }),
});

// Agent works on the branch (multiple commits)...

// Check if it can be merged cleanly
const compareRes = await fetch(
  'https://api.coregit.dev/v1/repos/agent-output/compare?base=main&head=agent-task-42',
  { headers: { 'x-api-key': process.env.COREGIT_API_KEY } }
);
const comparison = await compareRes.json();

if (comparison.mergeable) {
  // Merge into main
  await fetch(
    'https://api.coregit.dev/v1/repos/agent-output/branches/agent-task-42/merge',
    {
      method: 'POST',
      headers: {
        'x-api-key': process.env.COREGIT_API_KEY,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        target: 'main',
        strategy: 'squash',
        message: 'feat: implement user auth (agent-task-42)',
      }),
    }
  );
} else {
  console.log('Conflicts:', comparison.conflicts);
  // Handle conflicts or retry with a different approach
}

Cherry-Pick for Stacked Changes

When multiple agents work in sequence, use cherry-pick to replay changes:

// Agent A worked on commits base..headA on branch-a
// Agent B needs to replay those onto a different branch
const cherryPickRes = await fetch(
  'https://api.coregit.dev/v1/repos/agent-output/cherry-pick',
  {
    method: 'POST',
    headers: {
      'x-api-key': process.env.COREGIT_API_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      base: mergeBase,      // start of range (exclusive)
      head: agentAHead,     // end of range (inclusive)
      onto: 'dev',          // replay onto dev branch
      branch: 'dev',        // update dev branch with result
      expected_sha: devHead, // CAS — fail if dev moved
    }),
  }
);

const result = await cherryPickRes.json();
if (result.success) {
  console.log('Replayed onto dev:', result.head_sha);
} else {
  console.log('Conflicts:', result.conflicts);
}

Helper Function

Wrap the API in a reusable function:

class CoregitClient {
  constructor(private apiKey: string, private baseUrl = 'https://api.coregit.dev/v1') {}

  private async request(path: string, options?: RequestInit) {
    const res = await fetch(`${this.baseUrl}${path}`, {
      ...options,
      headers: {
        'x-api-key': this.apiKey,
        'Content-Type': 'application/json',
        ...options?.headers,
      },
    });
    if (!res.ok) throw new Error(`Coregit API error: ${res.status}`);
    return res.json();
  }

  createRepo(slug: string, visibility: 'private' | 'public' = 'private') {
    return this.request('/repos', {
      method: 'POST',
      body: JSON.stringify({ slug, visibility }),
    });
  }

  commit(repoSlug: string, branch: string, message: string, changes: any[]) {
    return this.request(`/repos/${repoSlug}/commits`, {
      method: 'POST',
      body: JSON.stringify({ branch, message, changes }),
    });
  }

  compare(repoSlug: string, base: string, head: string) {
    return this.request(`/repos/${repoSlug}/compare?base=${base}&head=${head}`);
  }

  cherryPick(repoSlug: string, base: string, head: string, onto: string, branch?: string) {
    return this.request(`/repos/${repoSlug}/cherry-pick`, {
      method: 'POST',
      body: JSON.stringify({ base, head, onto, branch }),
    });
  }

  merge(repoSlug: string, source: string, target: string, strategy: string = 'fast-forward') {
    return this.request(`/repos/${repoSlug}/branches/${source}/merge`, {
      method: 'POST',
      body: JSON.stringify({ target, strategy }),
    });
  }

  snapshot(repoSlug: string, name: string, branch: string) {
    return this.request(`/repos/${repoSlug}/snapshots`, {
      method: 'POST',
      body: JSON.stringify({ name, branch }),
    });
  }

  restore(repoSlug: string, snapshotName: string, targetBranch: string) {
    return this.request(`/repos/${repoSlug}/snapshots/${snapshotName}/restore`, {
      method: 'POST',
      body: JSON.stringify({ target_branch: targetBranch }),
    });
  }

  readFile(repoSlug: string, ref: string, path: string) {
    return this.request(`/repos/${repoSlug}/blob/${ref}/${path}`);
  }
}

// Usage
const git = new CoregitClient(process.env.COREGIT_API_KEY!);
await git.createRepo('my-project');
await git.commit('my-project', 'main', 'init', [
  { path: 'README.md', content: '# Hello' },
]);

// Compare and merge
const diff = await git.compare('my-project', 'main', 'feature');
if (diff.mergeable) {
  await git.merge('my-project', 'feature', 'main', 'squash');
}

On this page