---
sidebar_position: 8
title: Cloning Repositories
---

# Cloning Repositories in Custom Agents

Custom agents can clone your project's configured repositories (GitHub/GitLab) using the `cloneRepo()` helper function from `@zibby/core`.

## Overview

When your agent runs in the cloud, it has access to:
- All repositories configured in your project settings (GitHub/GitLab)
- Authenticated tokens for cloning (injected securely by the platform)
- A clean isolated container environment

The `cloneRepo()` function handles authentication, supports multiple repos, and works with both GitHub.com and self-hosted GitLab instances.

## Basic Usage

### Clone All Repositories

By default, `cloneRepo()` clones all repositories configured for your project:

```javascript
// nodes/setup.mjs
import { cloneRepo, z } from '@zibby/core';

const SetupOutputSchema = z.object({
  repoPaths: z.record(z.string()),
});

export const setupNode = {
  name: 'setup',
  
  async preProcess(state) {
    // Clone all repos
    const repoPaths = await cloneRepo();
    
    // repoPaths = {
    //   'myorg/backend': '/workspace/repos/myorg-backend',
    //   'myorg/frontend': '/workspace/repos/myorg-frontend'
    // }
    
    return { repoPaths };
  },
  
  prompt: (state) => `Repositories cloned:
${JSON.stringify(state.setup.repoPaths, null, 2)}

Ready to analyze the codebase.`,
  
  outputSchema: SetupOutputSchema,
};
```

### Clone Specific Repositories

If you only need certain repositories:

```javascript
// Clone only backend repo
const repoPaths = await cloneRepo({
  repos: ['myorg/backend']
});
```

### Using Cloned Repositories

Access the cloned code via the returned paths:

```javascript
// nodes/analyze.mjs
import { z } from '@zibby/core';

const AnalyzeOutputSchema = z.object({
  summary: z.string(),
  files: z.array(z.string()),
});

export const analyzeNode = {
  name: 'analyze',
  
  prompt: (state) => `Analyze the codebase.

Repositories are cloned at:
${JSON.stringify(state.setup.repoPaths, null, 2)}

Use the Shell tool to:
1. List files in the repos (e.g., ls ${Object.values(state.setup.repoPaths)[0]})
2. Read important files (e.g., cat ${Object.values(state.setup.repoPaths)[0]}/README.md)
3. Run analysis commands (e.g., cd ${Object.values(state.setup.repoPaths)[0]} && npm audit)

Return a summary and list of key files.`,
  
  outputSchema: AnalyzeOutputSchema,
};
```

## Configuration Options

```javascript
await cloneRepo({
  // Clone specific repos only (default: all repos)
  repos: ['myorg/backend', 'myorg/frontend'],
  
  // Base directory for cloned repos (default: '/workspace/repos')
  baseDir: '/workspace/repos',
  
  // Clone depth - 1 for shallow clone, 0 for full history (default: 1)
  depth: 1,
  
  // Specific branch to clone (default: repo's default branch)
  branch: 'develop',
});
```

## Return Value

`cloneRepo()` returns an object mapping repository names to their cloned paths:

```javascript
{
  'myorg/backend': '/workspace/repos/myorg-backend',
  'myorg/frontend': '/workspace/repos/myorg-frontend'
}
```

If a repository fails to clone, its value will be `null`:

```javascript
{
  'myorg/backend': '/workspace/repos/myorg-backend',
  'myorg/broken-repo': null  // Failed to clone
}
```

## Complete Example Agent

Here's a full agent that clones repos and runs analysis:

```javascript
// graph.mjs
import { WorkflowAgent, WorkflowGraph } from '@zibby/core';
import { setupNode, analyzeNode, reportNode } from './nodes/index.mjs';

export class CodeAuditWorkflow extends WorkflowAgent {
  buildGraph() {
    const graph = new WorkflowGraph();

    graph.addNode('setup', setupNode);
    graph.addNode('analyze', analyzeNode);
    graph.addNode('report', reportNode);

    graph.setEntryPoint('setup');
    graph.addEdge('setup', 'analyze');
    graph.addEdge('analyze', 'report');
    graph.addEdge('report', 'END');

    return graph;
  }
}
```

```javascript
// nodes/setup.mjs
import { cloneRepo, z } from '@zibby/core';

export const setupNode = {
  name: 'setup',
  
  async preProcess(state) {
    console.log('Cloning repositories...');
    const repoPaths = await cloneRepo();
    console.log('Cloned:', Object.keys(repoPaths).length, 'repositories');
    return { repoPaths };
  },
  
  prompt: () => 'Repositories cloned successfully. Ready for analysis.',
  
  outputSchema: z.object({
    ready: z.boolean().default(true),
  }),
};
```

```javascript
// nodes/analyze.mjs
import { z } from '@zibby/core';

export const analyzeNode = {
  name: 'analyze',
  
  prompt: (state) => {
    const repoList = Object.entries(state.setup.repoPaths)
      .map(([name, path]) => `- ${name}: ${path}`)
      .join('\\n');
    
    return `Analyze all cloned repositories for security issues.

Cloned repositories:
${repoList}

For each repository, use the Shell tool to:
1. Check for dependencies with known vulnerabilities (npm audit, pip check, etc.)
2. Search for common security issues (hardcoded secrets, SQL injection patterns, etc.)
3. Review package.json/requirements.txt for outdated dependencies

Return a comprehensive security audit report.`;
  },
  
  outputSchema: z.object({
    findings: z.array(z.object({
      severity: z.enum(['low', 'medium', 'high', 'critical']),
      repo: z.string(),
      description: z.string(),
      file: z.string().optional(),
    })),
    summary: z.string(),
  }),
};
```

## How It Works

1. **Project Configuration**: You configure repositories in your project settings (Web UI)
2. **Secure Token Injection**: When the agent runs, Zibby injects:
   - `REPOS` env var (array of repo metadata with clone URLs)
   - `GITHUB_TOKEN` and/or `GITLAB_TOKEN` (OAuth tokens for authentication)
3. **Authenticated Clone**: `cloneRepo()` constructs authenticated URLs and clones via `git clone`
4. **Isolation**: Each agent run gets a fresh container with no cached state

## Supported Platforms

- **GitHub** (github.com)
- **GitLab** (gitlab.com)
- **Self-hosted GitLab** (custom instance URLs from project settings)

## Error Handling

`cloneRepo()` is resilient to failures:

```javascript
const repoPaths = await cloneRepo();

// Check for failures
for (const [repo, path] of Object.entries(repoPaths)) {
  if (path === null) {
    console.error(`Failed to clone ${repo}`);
  }
}

// Continue with successfully cloned repos
const successfulRepos = Object.entries(repoPaths)
  .filter(([_, path]) => path !== null);
```

Common failure reasons:
- Missing/expired authentication tokens
- Repository doesn't exist or access denied
- Network issues
- Invalid clone URL

## Performance Tips

1. **Shallow Clones**: Use `depth: 1` (default) for faster cloning
2. **Specific Repos**: Only clone repos you need via the `repos` option
3. **Parallel Execution**: `cloneRepo()` clones all repos in parallel automatically

## Local Development

When running agents locally (`zibby agent run`), you'll need to:
1. Set `REPOS` env var manually (JSON array)
2. Provide `GITHUB_TOKEN` or `GITLAB_TOKEN`
3. Ensure `git` is installed

Example for local testing:

```bash
export REPOS='[{"name":"myorg/backend","provider":"github","cloneUrl":"https://github.com/myorg/backend.git"}]'
export GITHUB_TOKEN="ghp_your_token"
zibby agent run my-agent
```

In production (cloud), these are injected automatically.
