View as Markdown

Forkline CLI

The forkline CLI lets you manage repositories, runners, routines, MCP servers, secrets, tokens, and analytics from your terminal. It supports human-readable tables, structured JSON output for scripting, and shell completions.

Command aliases and prefix inference

The CLI accepts plural forms and long variants as aliases for the canonical singular resource nouns shown below — repo, repos, repository, and repositories all work identically. Verb synonyms are also accepted: view/get/show, list/ls, create/new/add, update/edit, delete/rm/remove. Unique prefixes are inferred automatically (e.g. rep... resolves to repo); ambiguous prefixes produce a clear error. Nothing is breaking — all old command forms keep working.

Installation

Install the forkline CLI via npm (recommended), the shell installer, a direct binary download, or from source. Every method produces the same binary; only shell completions require an extra step (see Shell completions below).

npm automatically selects the correct pre-built binary for your platform:

npm install -g @forkline/cli

Or run without installing:

npx @forkline/cli --version

npm installs a platform-specific optional dependency based on your OS, architecture, and libc:

Platform Package
Linux x86_64 (glibc) @forkline/cli-linux-x64-gnu
Linux x86_64 (musl) @forkline/cli-linux-x64-musl
Linux arm64 (glibc) @forkline/cli-linux-arm64-gnu
Linux arm64 (musl) @forkline/cli-linux-arm64-musl
macOS x86_64 @forkline/cli-darwin-x64
macOS arm64 @forkline/cli-darwin-arm64
Windows x86_64 @forkline/cli-win32-x64
Windows arm64 @forkline/cli-win32-arm64

Shell installer

The installer detects your OS, architecture, and libc (Linux glibc vs musl), downloads the latest release, verifies the SHA256 checksum, and installs the binary to /usr/local/bin if writable — otherwise $HOME/.local/bin.

curl -fsSL https://forkline.dev/install.sh | sh

Two environment variables control the installer:

Variable Description
FORKLINE_VERSION Pin a specific version (e.g. 0.37.2 or v0.37.2)
FORKLINE_INSTALL_DIR Override the install directory

Example:

FORKLINE_VERSION=0.37.2 FORKLINE_INSTALL_DIR=$HOME/bin \
  sh -c "$(curl -fsSL https://forkline.dev/install.sh)"

The shell installer supports Linux and macOS only. On Windows use npm or the direct download below.

Direct download

Grab the archive for your platform from GitHub Releases. Archives are named forkline-{version}-{target}.tar.gz (.zip on Windows):

Target Platform
x86_64-unknown-linux-gnu Linux x86_64 (glibc)
x86_64-unknown-linux-musl Linux x86_64 (musl, Alpine)
aarch64-unknown-linux-gnu Linux arm64 (glibc)
aarch64-unknown-linux-musl Linux arm64 (musl)
x86_64-apple-darwin macOS x86_64
aarch64-apple-darwin macOS arm64 (Apple Silicon)
x86_64-pc-windows-msvc Windows x86_64
aarch64-pc-windows-msvc Windows arm64

Every release ships a SHA256SUMS.txt you can verify locally:

sha256sum -c SHA256SUMS.txt

Then unpack and move the binary onto your PATH:

tar -xzf forkline-<version>-<target>.tar.gz
sudo mv forkline-<version>-<target>/forkline /usr/local/bin/forkline

Each archive also contains shell completions (bash, zsh, fish, powershell, elvish) and a man page — see the Tarball releases tip under Shell completions.

Build from source

Requires Rust stable and protoc, and a checkout of the (private) Calypso repository:

cargo install --path crates/calypso-cli --locked

The binary is installed as forkline (not calypso-cli).

Verify the install

forkline --version

Platform notices

  • macOS Gatekeeper — if macOS refuses the binary with “cannot be opened because it is from an unidentified developer”, run xattr -d com.apple.quarantine /usr/local/bin/forkline, or right-click the binary in Finder and choose Open.
  • Windows SmartScreen — Windows may show “Windows protected your PC”. Click More info → Run anyway.
  • Unsupported platforms — if no pre-built binary matches your platform, the npm package exits with an “Unsupported platform” error rather than building from source. Set FORKLINE_BINARY to point at a compatible binary, or open an issue on GitHub.

Shell completions

Installing the CLI puts the forkline binary on your PATH but does not enable shell completion automatically. Run forkline completions install once after installation; see forkline completions <shell> for details and per-shell options.

Authentication

First-time setup

forkline auth login

The CLI starts a browser-based sign-in: it prints a verification URL and short code, opens your browser when possible, and receives an API token automatically once you approve the request in the Forkline web app. The token is stored in your system keyring by default, or in a 0600-permissions file at ~/.config/forkline/credentials.toml if no keyring is available.

Without a browser

On SSH sessions or headless containers, skip the browser with --no-browser. The CLI prints the URL where you can create a Personal Access Token in the web UI (Settings → API Tokens) and waits for you to paste it:

forkline auth login --no-browser

Non-interactive login

Pipe a token via stdin:

echo "$FORKLINE_TOKEN" | forkline auth login --token-stdin

CI / headless environments

Set the FORKLINE_TOKEN environment variable. It takes priority over stored credentials:

export FORKLINE_TOKEN="fl_pat_v1_..."
forkline me

Profiles

The CLI supports named profiles for managing multiple accounts or environments:

forkline auth login --profile staging --api-url https://api.staging.forkline.dev/v1
forkline me --profile staging

The default profile is default with API URL https://api.forkline.dev/v1.

Quickstart

# Verify authentication
forkline me

# List repositories
forkline repo list

# View a specific repository
forkline repo view my-project

# List available runner sizes
forkline runner sizes

# Start a runner (consumes credits)
forkline runner start --repository my-project --size basic --wait

# List running runners
forkline runner list

# List routines
forkline routine list

# View analytics
forkline analytics overview

# Manage secrets (value via stdin, never argv)
echo "my-secret-value" | forkline secret set DB_PASSWORD --repository my-project --value-stdin

# Browse the MCP catalog and connect a server
forkline mcp catalog list --search grafana
forkline mcp create --from-catalog context7 --credential CTX7_KEY=account/CTX7_KEY --repository my-project --enable

# Create a token (shown once)
forkline token create --name "ci-token" --scopes "runners:read,runners:write"

Warning: Starting a runner consumes billing credits. Use forkline billing credits to check your balance.

Command reference

forkline auth

Subcommand Description
login Authenticate with a PAT (opens browser)
status Show current authentication status
logout Remove local credentials

forkline me

Display the authenticated user’s profile.

forkline repo

Subcommand Description
list List repositories
view <ref> View a repository by name or ID
create Register a new repository
update <ref> Update repository settings
delete <ref> Delete a repository
restore <ref> Restore a deleted repository
opencode-config <ref> View or update OpenCode configuration

forkline runner

Subcommand Description
list List runners
view <ref> View runner details
start Start a new runner
stop <ref> Stop a runner
restart <ref> Restart a runner
attach <ref> Attach a local OpenCode session to a runner’s current session
attach <ref> new Start a fresh OpenCode session instead of joining the runner’s current session
events <ref> View runner event history
wait <ref> Wait for a runner to reach a terminal state
settings get <ref> View runner settings
settings set <ref> --settings '<json>' Update runner settings from a JSON object (--settings, default {})
sizes List available runner sizes
bulk Bulk operations on runners

forkline routine

<ref> is a routine name, UUID or id prefix. Arguments written <file|ref> take a routine file when the path exists, otherwise a ref.

Subcommand Description
list List routines, with REPOS and LAST RUN columns
view <ref> View routine details
create -f <path> Create from a YAML or JSON file (--file; alias add). new is not an alias: it writes a local scaffold
update <ref> -f <path> Update from a YAML or JSON file
delete <ref> Delete a routine
publish <ref> Publish a routine
disable <ref> Disable a routine
enable <ref> Enable a disabled routine
run <ref> Run now. Does a dry run, prints the table and the estimate, asks to confirm (--yes skips it), then starts the runs. --payload <file|-> (webhook routines), --event <uuid> (event routines), --repository owner/name (repeatable), --dry-run, --show-prompt, --idempotency-key <key>, --wait (--timeout, default 300s; --poll-interval, default 5s; both are checked before anything is sent). The real run goes to the repositories that passed the dry run. Exit 9 when rate limited or busy (429)
webhook <ref> Show the webhook URL, the authentication method and the secret status of an on.webhook routine; --rotate-secret replaces a generated secret (refused with exit 2 before the rotate request is sent for a pasted one, nothing changes), --set-secret <file|-> stores the secret a vendor gave you
tasks <ref> List routine tasks
task <ref> <task_id> View a specific task
new [NAME] --example <name> Write a local routine file from an embedded example: review-prs, fix-ci, triage-issues, fix-command, weekly-deps, custom-webhook (--out PATH, --force)
new [NAME] --from-event <id> Write a local routine file drafted from a recent event (--fact KEY repeatable, --widen, --out PATH, --force)
validate <file|dir|ref>... Check files, directories or stored routines against the server rules without saving; exit 2 if any is invalid
test <file|ref> --event <id|file> Replay one event (a recent event ID, or a payload file with --forge and --event-header) and show each stage; or --repository owner/name [--body FILE] for schedule and webhook routines. --delivery-id <id> (payload file only), --prompt-only, --expect run|skip
backtest <file|ref> Replay the stored events of the last days (--since 1d..7d, --show would-run|skipped|all, --limit N) and estimate cost; --fail-if-zero exits 10 when nothing would have run: no event (event routines), no runs per week or no repository (schedules), no repository (webhooks)
runs <ref> List what a routine did with events (--outcome, --repo owner/name, --pr N, --since Nd, --limit N). Starts with a counts strip Ran · Skipped · Limited · Errors for the --since window; --outcome skipped also returns the limited runs
events List recent events your routines could react to (--repo, --event, --since, --reacted any|none|some, --limit). The last column is the event ID to pass to event and new --from-event; a hint on stderr says so
event <id> Show one recent event with its facts and what each routine did
push [PATH] Validate every file in .forkline/routines/ (.yaml, .yml, .json) or PATH, then create or update routines by name; writes nothing if any file is invalid. --dry-run prints the plan, --publish also publishes drafts and enables disabled routines, --yes skips confirmations
pull [REF]... Download stored routines to <dir>/<name>.yaml (--dir PATH, default .forkline/routines); a file with different content is skipped with exit 6 unless --force

new writes a local file only and never overwrites without --force (exit 6). validate, test, backtest, events and runs change nothing and work with a token that has only the routines:read scope. Every command accepts the global --json flag. With --json, list prints {"routines": [...]}, and run --wait prints the run response plus a tasks array (only when at least one task started).

forkline mcp

Manage MCP servers: browse the catalog, create and switch servers on and off, and store the credentials they reference. mcps and servers are aliases for mcp; cat is an alias for catalog.

The catalog and server endpoints are only available to accounts with MCP enabled. Without it those endpoints return 404 and the CLI reports that the resource was not found; forkline mcp secrets is not gated.

Subcommand Description
catalog list Browse the catalog: Verified servers first, then Unverified
catalog view <entry> Show one entry plus its revisions
list List your MCP servers with their status
view <server> Show one server, including its launch and credential bindings
create Create a server from a catalog entry (--from-catalog) or pasted JSON (--file)
update <server> Change name, repositories, non-secret inputs, credential bindings or a custom config
upgrade <server> Move a catalog server to another version (--dry-run shows what changes)
enable <server> Turn a server on
disable <server> Turn a server off
delete <server> Delete the server (asks for confirmation; --yes to skip)
preview --repository <ref> Show which servers apply to one repository and their state there
secrets list List account credentials (metadata only; values live in Vault) and the servers using each
secrets set <name> Create or rotate an account credential
secrets describe <name> Print a credential’s metadata. Note that this writes the description it sends
secrets delete <name> Delete an account credential

view, get and show are interchangeable verbs, ls for list, new/add for create, edit for update, rm/remove for delete. Servers are addressed by Server ID (slug) or UUID; a Server ID that matches more than one server is reported as ambiguous rather than guessed.

Catalog browsing

Option Description
--search <text> Substring match against title, slug and canonical name. A search also finds servers that are not available on Forkline
--limit <n> Page size (default: 50, clamped to 500 by the server)
--all Walk every page using the server’s cursor
--sort <order> name or updated (the default order is Verified first, then Unverified)

catalog list shows two groups, Verified first and then Unverified, with no filters. A server that cannot run on Forkline appears only in a search, with a not available: <slug> — <reason> line.

--sort is refused unless you pass --all. The server pages by keyset (group, then title) and after continues that order, so sorting one page locally would not match the cursor you would use for the next one. Ties keep the server’s order, which makes repeated runs byte-identical.

forkline mcp catalog list --search postgres
forkline mcp catalog view context7

Servers

Option Commands Description
--from-catalog <entry> create Catalog entry to install (external id or slug)
--version <version> create Catalog version (default: the latest installable one)
--file <path> create Pasted MCP JSON from Claude Code, Cursor, VS Code or OpenCode; - reads stdin
--server <key> create With --file: which server of the pasted JSON to create (needed when it holds several)
--name <text>, --slug <id> create, update Display name and Server ID (defaults: the catalog title or pasted key)
--credential <name>=<ref> create, update, upgrade Bind a declared credential to a stored secret, e.g. CTX7_KEY=account/CTX7_KEY (repeatable; on update it replaces all bindings)
--input <name>=<value> create, update, upgrade A non-secret input (repeatable; on update it replaces all inputs)
--repository <ref> create, update, list, preview On create/update: a repository to include, owner/name, a glob such as acme/*, or a UUID (repeatable; default: all). On list/preview: narrow to one repository
--all-repositories update Include every repository
--exclude <ref> create, update A repository to exclude (repeatable)
--enable create Turn the server on right away (it is saved off otherwise)
--config-file <path> update JSON config for a custom server; - reads stdin
--to-version <version> upgrade Target version (default: the latest installable one)
--dry-run upgrade Show what would change and stop
--repositories view List the repositories the server reaches, with its state on each
--status <status> list working, failing, needs_setup, unavailable, not_used_yet or off
forkline mcp create --from-catalog context7 \
  --credential CTX7_KEY=account/CTX7_KEY \
  --repository 'acme/*' --enable
cat mcp.json | forkline mcp create --file - --server grafana
forkline mcp list --status failing
forkline mcp preview --repository acme/api
forkline mcp view context7 --repositories
forkline mcp upgrade context7 --to-version 3.3.0 --dry-run
forkline mcp disable context7

The status says whether a server runs, never how it was applied. unavailable means a problem on our side (“Not running on this repository right now. This is on our side and we’ve been alerted.”). A server that is incomplete is saved off and reads needs_setup; enable it once its required inputs and credentials are filled in.

With no --repository, a server targets every repository you own. The server evaluates owner/name globs per repository, so the CLI cannot say locally which repositories a glob will match: use view --repositories (one server) or preview (one repository).

--credential takes a reference to a stored secret, never a value. The binding is NAME=account/<SECRET> or NAME=repo/<SECRET>, and the secret name must be ^[A-Z_][A-Z0-9_]*$. The env:VAR form that appears inside an install plan is a placeholder the runner resolves, not a binding; the CLI rejects it with that explanation rather than letting the API reject it later. --input values are sent in the request body and may appear in logs, so keep anything secret out of them. When --file finds a literal secret-looking value in the pasted JSON, the CLI warns on stderr; store it with secrets set and bind it with --credential.

preview prints one row per server that applies to the repository. The table also lists the read-only servers from OpenCode settings and the repository settings, marked read only (and replaced by <server> when a server above overrides one); -o json and -o jsonl print the whole view (servers, raw, warnings). It reports on stderr any warning: <server>: <message>, for example a declared credential that has no stored value.

Account credentials

pass show personal/grafana/token | forkline mcp secrets set GRAFANA_TOKEN --value-stdin
forkline mcp secrets set GRAFANA_TOKEN --value-env GRAFANA_TOKEN
forkline mcp secrets list
forkline mcp secrets describe GRAFANA_TOKEN --description "Grafana viewer token"
forkline mcp secrets delete GRAFANA_TOKEN

secrets set reads the value from stdin (--value-stdin), from a named environment variable (--value-env <VAR>), or by prompting on a terminal. There is no --value flag: command-line arguments are visible to any process through ps(1) and /proc/<pid>/cmdline, and for the whole lifetime of the process in some configurations. Non-interactive use without --value-stdin or --value-env is refused. A trailing newline from a pipe is stripped.

secrets describe is the one command to be careful with: it is implemented as PATCH /me/secrets/{name}, and the description it sends replaces the stored one. forkline mcp secrets describe GRAFANA_TOKEN --description "…" sets it; forkline mcp secrets describe GRAFANA_TOKEN with no --description prints the metadata and clears the stored description. For a read-only listing use secrets list.

secrets list shows names and when each was last rotated. Values are write-only — the API stores them in Vault and no read endpoint returns them. Deleting a credential leaves the servers that reference it in place; they read needs_setup until it is provided again.

forkline model

Subcommand Description
list List available AI models
providers List model providers

forkline connector

Subcommand Description
list List configured connectors (read-only)

forkline analytics

Subcommand Description
overview Usage overview
providers Usage by provider
models Usage by model
repositories Usage by repository
history Historical usage

All analytics subcommands accept --from and --to (YYYY-MM-DD).

forkline secret

Subcommand Description
list --repository <ref> List secrets for a repository
set <name> --repository <ref> Set a secret value (via --value-stdin or --value-env)
delete <name> --repository <ref> Delete a secret

forkline token

Subcommand Description
list List your API tokens
create --name <n> --scopes <s> Create a token (value shown once)
revoke <ref> Revoke a token

forkline provider

Subcommand Description
list List custom AI providers
import --file <path> Import a custom provider from JSON
delete <id> Delete a custom provider

Routine definitions

Routines are defined as YAML (or JSON) files. Create or update them with forkline routine create --file <path> / forkline routine update <ref> --file <path>, or sync a directory with forkline routine push [PATH] (defaults to .forkline/routines/). A file ending in .json is read as JSON, anything else as YAML. name and description sit beside the spec fields:

name: weekly-deps
description: Update dependencies every Monday
on:
  schedule:
    cron: "0 6 * * 1"
    timezone: Europe/Berlin
repositories:
  include:
    - name: "acme/*"
agent:
  prompt: Update outdated dependencies in {{ repository.fullName }} and open a PR.

The same routine as JSON:

{
  "name": "weekly-deps",
  "on": { "schedule": { "cron": "0 6 * * 1", "timezone": "Europe/Berlin" } },
  "repositories": { "include": [{ "name": "acme/*" }] },
  "agent": { "prompt": "Update outdated dependencies in {{ repository.fullName }} and open a PR." }
}

on takes exactly one of events, schedule and webhook. The Routines guide (not published yet) covers events, filters, the when condition, template variables, repositories, agent settings and limits.

A typical loop is forkline routine new --example review-prs, edit the file, forkline routine validate <file>, forkline routine backtest <file>, forkline routine test <file> --event <id>, then forkline routine push --publish. Use forkline routine pull to download routines that were created elsewhere.

If the server rejects a definition, the CLI prints one line per problem as file:line: message (pointer) (file: message (pointer) when the line is unknown), and exits with code 2:

routine.yaml:9: Unknown field `inlcude`. Allowed here: `include`, `exclude`. Did you mean `include`? (/filters/labels/inlcude)

Custom webhook secrets

A routine with on.webhook and a token or preset: forkline gets a secret when it is created. The CLI prints it once, with a notice that it will not be shown again; store it then. For preset: github and preset: sentry the sender holds the secret: store it with forkline routine webhook <ref> --set-secret secret.txt (or - for stdin). Forkline never shows it back. Use forkline routine webhook <ref> to print the webhook URL, the authentication method (for a token, the header name too, so a custom header is not mistaken for Authorization) and whether a secret is configured and where it came from, and forkline routine webhook <ref> --rotate-secret to replace a generated secret (the old one stops working at once; it asks for confirmation, or pass --yes in scripts). The flags exclude each other.

forkline billing

Subcommand Description
credits Show current credit balance

forkline config

Subcommand Description
path Show configuration file path
view Show resolved configuration
list-profiles List configured profiles
set-profile <name> Create or update a profile (use --api-url to set API URL)
use-profile <name> Set the default profile

forkline completions <shell>

Generate shell completions. Supported shells: bash, zsh, fish, powershell, elvish.

The command prints a completion script to stdout. You must install it into your shell’s completion directory — installing the CLI does not enable shell completion automatically.

Recommended: one-command install

Run forkline completions install to auto-detect your shell and install completions to the correct location. Re-run after upgrades to update the script.

forkline completions install

Or specify a shell explicitly:

forkline completions install zsh

Tarball releases

Tarball archives from GitHub Releases include pre-generated completion files under completions/ (forkline.bash, _forkline, forkline.fish, etc.) and a man page. You can copy those files directly instead of regenerating with forkline completions.

zsh

Choose one of the following methods.

Option 1 — oh-my-zsh (recommended if you use oh-my-zsh):

mkdir -p "${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/completions"
forkline completions zsh > "${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/completions/_forkline"
exec zsh

Option 2 — plain zsh (user directory, no root required):

mkdir -p ~/.zfunc
forkline completions zsh > ~/.zfunc/_forkline

Then add these two lines to your ~/.zshrc in this order — fpath must be updated before compinit runs:

fpath=($HOME/.zfunc $fpath)
autoload -Uz compinit && compinit

If completions still do not appear after restarting your shell, clear the completion cache and restart:

rm -f ~/.zcompdump*
exec zsh

Why ordering matters

compinit indexes the directories in fpath at the time it runs. If fpath is updated after compinit, the new directory is ignored until the next compinit call or until ~/.zcompdump is deleted.

Option 3 — system-wide (requires sudo):

forkline completions zsh | sudo tee /usr/local/share/zsh/site-functions/_forkline >/dev/null

bash

System-wide (requires bash-completion and sudo):

forkline completions bash | sudo tee /etc/bash_completion.d/forkline >/dev/null

Per-user (loaded automatically by bash-completion):

mkdir -p ~/.local/share/bash-completion/completions
forkline completions bash > ~/.local/share/bash-completion/completions/forkline

Per-user (appended to .bashrc):

forkline completions bash >> ~/.bashrc
source ~/.bashrc

fish

mkdir -p ~/.config/fish/completions
forkline completions fish > ~/.config/fish/completions/forkline.fish

powershell

forkline completions powershell

Add the output to your PowerShell profile. Run echo $PROFILE to find its location.

elvish

forkline completions elvish

Add the output to your Elvish configuration (typically ~/.config/elvish/rc.elv).

forkline man

Generate a man page (roff format) to stdout:

forkline man > ~/.local/share/man/man1/forkline.1

forkline schema

Print a machine-readable JSON description of the entire CLI command tree, generated directly from the CLI’s own parser definitions. Requires no authentication, network access, or configuration file. Useful for tooling and AI agents that want to discover exact command/argument names, types, defaults, environment variables, and conflicts without parsing human help text:

forkline schema

The document is versioned independently of the CLI release (schema_version), so consumers should check that field before relying on the structure.

forkline agent-guide

Print a machine-readable JSON guide intended for AI coding agents operating the CLI: a catalog of top-level commands (with auth requirements and subcommands), output-format conventions, non-interactive flags, destructive-operation names, exit codes (including partial bulk failure), and general tips. Requires no authentication:

forkline agent-guide

Output modes

Control output with --output (or FORKLINE_OUTPUT):

Mode Description
human Aligned key-value pairs (default for terminals)
json Pretty-printed JSON objects
jsonl One JSON object per line (streaming)
quiet IDs only, one per line

-o is the short form of --output. --json is a global shorthand for --output json; it wins over FORKLINE_OUTPUT but cannot be combined with an explicit --output or -o. With --json, an error is also printed to stdout as {"error": {"kind", "code", "message", "http_status", "request_id", "retry_after_seconds", "issues"}}, and the exit code still tells you what failed.

stdout / stderr contract: Data output goes to stdout. Progress messages, prompts, and errors go to stderr. This allows piping data output while still seeing errors.

# Pipe JSON to jq
forkline repo list --output json | jq '.items[].name'

# Collect IDs only
forkline runner list --output quiet > runner-ids.txt

Exit codes

Code Meaning
0 Success
1 General error (API error including 413 payload too large, transport failure, a response the CLI cannot decode, I/O error)
2 Usage error (invalid arguments, config error, ambiguous reference, or a routine file the server rejects with 422; also routine run when the server refuses it with 422, when nothing can run, or when it needs a confirmation and has no terminal)
3 Authentication error (invalid or missing token)
4 Authorization error (missing scope or insufficient permissions)
5 Not found (resource does not exist or you lack access)
6 Conflict (resource already exists or state conflict; routine new and routine pull refusing to overwrite a file)
7 Connection error (cannot reach API server)
8 Timeout (request or connection timed out)
9 Rate limited or overloaded (429; check retry_after). routine run uses it when Forkline is busy or the limit of 10 real runs a minute is reached
10 Expectation failed (routine test --expect does not match, or routine backtest --fail-if-zero finds nothing that would run: no event for event routines, no runs per week or no repository for schedules, no repository for webhooks), or partial bulk runner failure (some operations succeeded, some failed)
130 Interrupted (Ctrl+C / SIGINT)

Changes

Breaking changes to the CLI, for scripts written against earlier versions:

  • forkline runner settings set takes its JSON in --settings (it was --json). --json is now the global output flag.
  • --json is a global flag for every command, the same as --output json. -o is the short form of --output.
  • forkline routine list --json prints {"routines": [...]}.
  • forkline routine new writes a local scaffold and is no longer an alias of routine create. create keeps the alias add.
  • forkline routine run --wait --json prints the run response with a tasks array of the final task states, only when at least one task started.
  • Responses are decoded strictly: an unknown value or a missing field exits with code 1 and failed to decode response, instead of being tolerated. --json on the routine commands that print the server document as is (runs, events, event, test, backtest, new --from-event) prints it even when this CLI cannot decode it.

Custom provider import

Import a custom AI provider from JSON using forkline provider import --file <path>:

{
  "provider": {
    "my-provider": {
      "name": "My Custom Provider",
      "npm": "@ai-sdk/example",
      "models": {
        "model-1": {
          "name": "Model 1",
          "contextWindow": 128000,
          "modalities": {
            "input": ["text"],
            "output": ["text"]
          }
        }
      },
      "options": {
        "baseURL": "https://api.example.com/v1"
      }
    }
  }
}

Note: baseURL must be nested under options; the API rejects a top-level baseURL field. contextWindow uses camelCase (matching the API); the snake_case form context_window is also accepted for convenience. Exactly one provider may be included per import file.

OpenCode configuration

Manage a repository’s OpenCode configuration with forkline repo opencode-config:

# View current OpenCode config
forkline repo opencode-config get my-repo

# Set OpenCode config from a file
forkline repo opencode-config set my-repo --file opencode-config.json

# Set OpenCode config from stdin (use --file -)
echo '{"instructions":["Be helpful"]}' | forkline repo opencode-config set my-repo --file -

# Delete OpenCode config (requires --yes when non-interactive)
forkline repo opencode-config delete my-repo --yes

The config is a free-form JSON object validated against the bundled OpenCode settings schema; the keys permission, autoupdate, model, and provider are reserved for the platform and rejected. Allowed keys include logLevel, mcp, and instructions, for example:

{
  "logLevel": "INFO",
  "mcp": {},
  "instructions": ["Be helpful"]
}

Safety and confirmations

Destructive operations (delete, stop, revoke) prompt for confirmation in interactive mode. In non-interactive mode (piped stdin or --no-input), these commands require --yes:

forkline runner stop my-runner --yes
forkline token revoke old-token --yes

The --no-input flag (or FORKLINE_NO_INPUT=true) disables all interactive prompts. Combined with --yes, it allows fully scripted usage.

Environment variables

Variable Description
FORKLINE_TOKEN API token (takes priority over stored credentials)
FORKLINE_API_URL Override the API base URL
FORKLINE_PROFILE Select a configuration profile
FORKLINE_OUTPUT Default output format (human, json, jsonl, quiet)
FORKLINE_NO_INPUT Disable interactive prompts (true or false)
FORKLINE_YES Auto-confirm destructive operations (true or false)
FORKLINE_LOG Tracing filter for debug logs (e.g. debug, forkline=trace)

Troubleshooting

Symptom Cause Fix
Exit code 3 Invalid or expired token Run forkline auth login or check FORKLINE_TOKEN
Exit code 4 Missing API scope Recreate token with required scopes
Exit code 7 Cannot reach API Check network, FORKLINE_API_URL, and --connect-timeout
Exit code 8 Request timed out Increase --timeout (e.g. --timeout 120s)
Exit code 9 Rate limited, or Forkline is busy Wait for retry_after seconds
Exit code 10 Expectation failed, or partial bulk runner failure routine test --expect did not match, or routine backtest --fail-if-zero found nothing that would run; or some bulk runner operations succeeded and some failed (check the output for details)

Enable debug logging with FORKLINE_LOG=debug for detailed request/response traces.