---
title: "Setup Scripts"
description: "Automate your development environment with .forkline setup scripts."
section: "configuration"
url: "https://forkline.dev/docs/repositories/setup-scripts"
markdown: "https://forkline.dev/docs/repositories/setup-scripts.md"
source: "src/content/docs/repositories/setup-scripts.mdx"
---

# Setup Scripts

Automate runner initialization with `.forkline/setup.sh` and `.forkline/setup.rh`. Both run after git clone and before the AI agent starts.

## Overview

Setup scripts are useful when a repository needs repeatable preparation before work begins:

- Install dependencies
- Configure the environment
- Set up local databases or services
- Run migrations
- Prepare tools and utilities

> **Info**: Setup scripts live in your repository, so the setup process is version-controlled alongside the code it supports.

_Interactive figure (SetupScriptsDiagram) — see the HTML version of this page._

## Script Types

| Script | Format | Best For |
|--------|--------|----------|
| `.forkline/setup.rh` | Rash (YAML) | Declarative, idempotent setup |
| `.forkline/setup.sh` | Bash | Imperative commands and glue scripts |

## Bash Scripts (`.forkline/setup.sh`)

### Basic Example

```bash
#!/bin/bash
set -euo pipefail

# Install dependencies
npm install

# Run database migrations
npm run db:migrate

# Seed test data
npm run db:seed
```

### Using Secrets

Repository secrets are available as environment variables:

```bash
#!/bin/bash
set -euo pipefail

# Secrets are automatically available
echo "Setting up database..."
export DATABASE_URL="$DATABASE_URL"

# Run migrations
npm run db:migrate

# Configure API clients
export STRIPE_API_KEY="$STRIPE_API_KEY"
```

> **Warning**: Setup script failures are non-fatal. The runner continues to start, but the environment may be incomplete. Check logs if the workspace behaves unexpectedly.

## Rash Scripts (`.forkline/setup.rh`)

Rash is a declarative YAML-based shell language designed for container workflows.

### Basic Example

```yaml
#!/bin/rash
- name: Install dependencies
  command:
    argv: [npm, install]

- name: Run migrations
  command:
    argv: [npm, run, db:migrate]

- name: Create .env file
  copy:
    content: |
      DATABASE_URL={{ env.DATABASE_URL }}
      API_KEY={{ env.API_KEY }}
    dest: .env
    mode: "600"
```

## Script Behavior

| Property | Value |
|----------|-------|
| Working directory | Repository root |
| Environment | Secrets are injected as env vars |
| Timeout | 5 minutes per script |
| Failure | Non-fatal, logged, runner continues |

## Debugging Setup Scripts

If your runner behaves unexpectedly, the setup script may have failed. Here's how to find out what went wrong.

### Ask the Runner

When you connect to a runner and notice missing tools or configuration, simply ask the runner about it. Say something like:

> "I think the setup script didn't work. Can you check the setup logs?"

The runner will check `/tmp/.forkline-setup.log` and report what happened.

### What to Look For

Setup script logs contain:

| Field | Description |
|-------|-------------|
| Script | Which script ran (`.forkline/setup.rh` or `.forkline/setup.sh`) |
| Interpreter | Whether it was `rash` or `bash` |
| Status | `SUCCESS`, `FAILED`, or `TIMEOUT` |
| Exit Code | The numeric exit code if it failed |
| Duration | How long it took |
| Secrets Injected | How many repository secrets were passed |
| STDOUT | Output from the script |
| STDERR | Error messages |

### Common Issues

**Missing tools**

Scripts may fail because required CLI tools aren't installed in the runner:

```bash
# Example error in STDERR
npm: command not found
pip: command not found
```

**Solution**: Ensure your setup script checks for prerequisites or installs them.

**Missing secrets**

Scripts expecting environment variables that weren't configured:

```bash
# Example error
$DATABASE_URL: unbound variable
```

**Solution**: Add the secret in repository settings before starting the runner.

**Permission errors**

Scripts trying to write to protected directories:

```bash
# Example error
Permission denied: /usr/local/bin/tool
```

**Solution**: Write to the workspace directory (`.`) or use user-writable paths.

**Timeouts**

Scripts taking longer than 5 minutes:

```
# Example log entry
Status: TIMEOUT
Duration: 300000ms
```

**Solution**: Optimize the script or break it into smaller steps.

## Next Steps

- [Configure repository secrets](https://forkline.dev/docs/repositories/secrets)
- [Start a runner](https://forkline.dev/docs/runners/starting) to test scripts
- [Learn about Rash](https://rash-sh.github.io/docs/rash/v2.17/) for advanced setups
