Skip to content

Add Replicate as a delegated run provider #691

Description

@coygeek

Summary

Add a built-in replicate provider that can run Crabbox commands through a Replicate prediction or deployment backed by a compatible Crabbox runner model.

Replicate is not an SSH host or a general-purpose VM lease API. Its public control plane is centered on predictions, deployments, model versions, logs, output files, cancellation, and optional streaming. Because of that, the provider should be implemented as ProviderKindDelegatedRun, not ProviderKindSSHLease, and should be explicit that it requires a Replicate model or deployment whose input and output schema implements Crabbox's runner contract.

Motivation

Crabbox already supports providers that do not expose SSH by using delegated run backends, for example Modal, Freestyle, OpenComputer, CodeSandbox, and Upstash Box. Replicate can fit the same provider family if Crabbox treats Replicate prediction IDs as run/session handles and delegates workspace upload, command execution, log polling, cancellation, and output mapping to a runner model.

This would let users run:

REPLICATE_API_TOKEN=... crabbox run --provider replicate -- npm test

or configure a specific deployment:

provider: replicate
replicate:
  deployment: example-org/crabbox-runner
  workdir: /workspace/crabbox
  waitSecs: 60
  execTimeoutSecs: 3600

Replicate API facts

Relevant API and platform details from the Replicate documentation:

  • Authentication uses Authorization: Bearer $REPLICATE_API_TOKEN.
  • Predictions can be created with POST https://api.replicate.com/v1/predictions.
  • Predictions can be fetched with GET https://api.replicate.com/v1/predictions/{prediction_id}.
  • Predictions can be listed with GET https://api.replicate.com/v1/predictions.
  • Predictions can be canceled with POST https://api.replicate.com/v1/predictions/{prediction_id}/cancel.
  • Deployment-backed predictions can be created with POST https://api.replicate.com/v1/deployments/{deployment_owner}/{deployment_name}/predictions.
  • Replicate supports Prefer: wait for initial synchronous waiting.
  • Prediction statuses include non-terminal and terminal lifecycle states such as starting, processing, succeeded, failed, and canceled.
  • File inputs should be HTTP URLs or data URLs.
  • Output files are represented as HTTPS URLs and may require the same Authorization header to fetch.
  • Deployments provide stable endpoints and hardware/scaling control, but billed runtime includes setup, idle, active, failed, and canceled deployment instance time as documented by Replicate.

Proposed provider shape

Provider metadata

Use canonical provider name replicate with no aliases initially.

Recommended ProviderSpec:

core.ProviderSpec{
    Name:        "replicate",
    Family:      "replicate",
    Kind:        core.ProviderKindDelegatedRun,
    Targets:     []core.TargetSpec{{OS: core.TargetLinux}},
    Features:    core.FeatureSet{core.FeatureArchiveSync, core.FeatureRunSession},
    Coordinator: core.CoordinatorNever,
}

Do not advertise SSH, desktop, browser, code-server, Crabbox-owned sync, cleanup, pause/resume, run artifacts, or run downloads until those contracts are implemented and tested.

Runner contract requirement

The first implementation should document and enforce that replicate requires either:

  1. A configured Replicate deployment, for example owner/name, that runs a Crabbox runner model, or
  2. A configured model version, only if direct version predictions can satisfy the same runner schema.

Suggested runner input schema:

{
  "archive": "https://... or data:application/gzip;base64,...",
  "command": ["npm", "test"],
  "shell": false,
  "workdir": "/workspace/crabbox",
  "env": {"KEY": "value"},
  "timeout_secs": 3600,
  "sync_delete": true
}

Suggested runner output schema:

{
  "exit_code": 0,
  "stdout": "optional final stdout",
  "stderr": "optional final stderr",
  "artifacts": []
}

The provider should fail fast with a clear error if the prediction output does not include a valid command exit code. A Replicate succeeded status should not automatically mean the command passed unless the runner output reports exit code 0.

Implementation plan

1. Add provider package

Add a new package:

internal/providers/replicate/
  provider.go
  backend.go
  client.go
  flags.go
  core.go
  sync.go
  *_test.go

Follow delegated provider patterns from:

  • internal/providers/opencomputer
  • internal/providers/modal
  • internal/providers/freestyle

opencomputer is the closest security and REST-client reference because it keeps API keys out of Crabbox config and sends credentials only in request headers.

2. Register provider

Update:

  • internal/providers/all/all.go, add side-effect import for internal/providers/replicate.
  • internal/providers/all/all_test.go, add coverage that:
    • ProviderFor("replicate") resolves.
    • Name() is replicate.
    • Family is replicate.
    • Kind is ProviderKindDelegatedRun.
    • Coordinator is CoordinatorNever.
    • target is Linux.
    • features are truthful for the implemented contract.
    • no accidental aliases are registered.
    • provider implements DoctorProvider, if the repository's current all-provider doctor contract remains required.

3. Add config and flags

Update internal/cli/config.go with a ReplicateConfig and YAML mapping.

Suggested config fields:

type ReplicateConfig struct {
    APIURL          string
    Deployment      string
    Version         string
    Workdir         string
    WaitSecs        int
    PollIntervalSecs int
    ExecTimeoutSecs int
    CancelAfterSecs int
    MaxArchiveBytes int64
}

Defaults:

  • APIURL: https://api.replicate.com
  • Workdir: /workspace/crabbox
  • WaitSecs: 60, capped to Replicate's supported wait behavior
  • PollIntervalSecs: a small nonzero default such as 2
  • ExecTimeoutSecs: 3600

Credential handling:

  • Read token from CRABBOX_REPLICATE_API_TOKEN, then REPLICATE_API_TOKEN.
  • Do not add the API token to Config, YAML, flags, logs, or command-line arguments.
  • Redact the token from HTTP error bodies.
  • Refuse cross-origin redirects so the bearer token cannot leak to another host.

Suggested flags:

  • --replicate-api-url, trusted CLI-only override for tests and development
  • --replicate-deployment
  • --replicate-version
  • --replicate-workdir
  • --replicate-wait-secs
  • --replicate-poll-interval-secs
  • --replicate-exec-timeout-secs
  • --replicate-cancel-after-secs
  • --replicate-max-archive-bytes

The implementation should require exactly one of deployment or version unless a future auto-discovery contract is added.

4. Implement REST client

Create a small internal client rather than depending on Replicate SDKs.

Client responsibilities:

  • Build requests against the configured API URL.
  • Send Authorization: Bearer <token>.
  • Send JSON request bodies.
  • Support Prefer: wait on prediction creation when configured.
  • Decode prediction responses, including:
    • id
    • status
    • logs
    • output
    • error
    • urls.get
    • urls.cancel
    • timestamps and metrics when available
  • Create predictions through either:
    • /v1/deployments/{owner}/{name}/predictions
    • /v1/predictions with a configured version
  • Poll prediction state until terminal status.
  • Cancel a prediction on context cancellation or crabbox stop.
  • List predictions for crabbox list, filtering locally when possible to Crabbox-created predictions.
  • Redact token values from all surfaced errors.

5. Implement delegated backend

Implement core.DelegatedRunBackend:

  • Warmup

    • Validate configuration and token.
    • Optionally check the configured deployment/version can be reached.
    • Print clearly that Replicate does not create a reusable SSH lease.
    • If a runner supports a lightweight health prediction, use it; otherwise avoid consuming GPU time just to warm up.
  • Run

    • Reject unsupported delegated sync options using core.RejectDelegatedSyncOptionsForSpec.
    • Build the portable sync archive with existing archive sync helpers.
    • Convert the archive into an accepted Replicate file input.
    • Create a prediction.
    • Treat prediction ID as the run session lease ID, or store a local claim if needed for slug/status/stop consistency.
    • Stream or periodically print logs without duplicating already printed content.
    • Map terminal status:
      • succeeded plus runner exit_code == 0 to Crabbox success.
      • succeeded plus nonzero runner exit_code to ExitError{Code: exit_code}.
      • failed to a Crabbox failure with Replicate error/log context.
      • canceled to a Crabbox canceled/stopped failure.
    • Cancel the prediction when the local context is canceled.
  • List

    • Return active/recent predictions as LeaseView entries when identifiable as Crabbox runs.
    • Prefer local claims or runner metadata to avoid showing unrelated predictions from the same account.
  • Status

    • Resolve a prediction ID or local claim.
    • Fetch and map prediction status to StatusView.
  • Stop

    • Resolve a prediction ID or local claim.
    • Call prediction cancel.
    • Remove local claim only after terminal cancellation or a clear not-found/stale-claim path.

6. Solve archive input strategy

Replicate accepts file inputs as HTTP URLs or data URLs, which is the main design decision for this provider.

Initial safe approach:

  • Support data URLs for small archives only.
  • Enforce replicate.maxArchiveBytes.
  • Error with a clear message when the archive is too large.

Future larger-workspace approaches:

  • Add a signed object storage upload path.
  • Use a separate Crabbox-controlled upload endpoint.
  • Use a runner-side pull URL if the user's repo or artifact bundle is already available through a short-lived URL.

The first implementation should not silently upload source code to an unspecified third-party store.

7. Add provider docs and provider matrix metadata

Add:

  • docs/providers/replicate.md

Update:

  • docs/providers/provider-metadata.json
  • docs/source-map.md
  • docs/providers/README.md, generated by node scripts/generate-provider-matrix.mjs
  • internal/cli/provider_categories_generated.go, generated by the same script

Suggested metadata:

"replicate": {
  "status": "built-in",
  "category": "delegated-sandbox",
  "substrate": "Replicate prediction or deployment backed by a Crabbox runner model",
  "location": "cloud",
  "ssh": "no",
  "sync": "archive-sync",
  "gpu": "optional",
  "lifecycle": "Replicate prediction",
  "cleanup": "prediction cancellation",
  "bestFit": "GPU-backed delegated command execution through a purpose-built Replicate runner",
  "caveat": "Requires a compatible runner model or deployment; Replicate is not a generic SSH lease",
  "docs": "replicate.md"
}

Docs must emphasize:

  • REPLICATE_API_TOKEN or CRABBOX_REPLICATE_API_TOKEN is required.
  • Token should come from a secret manager or environment, not YAML.
  • A compatible runner model/deployment is required.
  • No SSH, desktop, browser, code-server, or Crabbox-owned rsync support.
  • Large workspaces require an upload strategy beyond data URLs.
  • Replicate billing behavior may charge for setup, idle, active, failed, and canceled deployment instance time depending on the selected model/deployment.

8. Add tests

Add offline tests for:

  • Provider registration and ProviderSpec.
  • Flag application and config validation.
  • Token resolution precedence.
  • Missing token error.
  • API URL validation, including HTTPS-only except loopback development endpoints if desired.
  • Cross-origin redirect refusal.
  • Authorization header construction.
  • Token redaction from JSON and plain-text errors.
  • Prediction creation for deployment and version modes.
  • Prefer: wait header behavior.
  • Polling lifecycle mapping for starting, processing, succeeded, failed, and canceled.
  • Log streaming deduplication.
  • Context cancellation calls prediction cancel.
  • Stop calls cancel and handles already-canceled/not-found cases safely.
  • Archive size enforcement and data URL construction.
  • Nonzero runner exit code mapping.
  • Malformed runner output error.
  • Delegated sync option gating.

Files likely touched

Core/provider registry:

  • internal/providers/all/all.go
  • internal/providers/all/all_test.go
  • internal/cli/config.go

New provider:

  • internal/providers/replicate/provider.go
  • internal/providers/replicate/backend.go
  • internal/providers/replicate/client.go
  • internal/providers/replicate/flags.go
  • internal/providers/replicate/core.go
  • internal/providers/replicate/sync.go
  • internal/providers/replicate/*_test.go

Docs and generated metadata:

  • docs/providers/replicate.md
  • docs/providers/provider-metadata.json
  • docs/providers/README.md
  • docs/source-map.md
  • internal/cli/provider_categories_generated.go

Acceptance criteria

  • crabbox providers lists replicate with delegated-run, Linux, archive-sync, no SSH, and no coordinator support.
  • crabbox run --provider replicate -- <command> creates a Replicate prediction against the configured deployment or version.
  • The provider uploads or embeds the workspace archive only through an explicit supported input mechanism.
  • Replicate prediction logs are streamed or printed in order without repeated log spam.
  • Local cancellation cancels the prediction.
  • crabbox stop <id> cancels the prediction.
  • crabbox status <id> reports prediction state.
  • crabbox list --provider replicate does not show unrelated account predictions unless they can be identified as Crabbox-created runs.
  • A Replicate succeeded prediction with runner exit_code != 0 exits Crabbox with that command code.
  • API tokens never appear in config, argv, logs, errors, or redirected requests.
  • Offline tests cover all client and lifecycle behavior.
  • Provider docs clearly state the runner-model requirement and limitations.

Validation before PR

Focused validation:

gofmt -w $(git ls-files '*.go')
go test -race ./internal/providers/replicate ./internal/providers/all ./internal/cli
go vet ./...
node scripts/generate-provider-matrix.mjs
node scripts/check-provider-matrix.mjs
scripts/check-docs.sh

Full validation if the PR also touches worker or broader generated docs:

go test -race ./...
go build -trimpath -o bin/crabbox ./cmd/crabbox
scripts/test-go-modules.sh
scripts/check-go-coverage.sh 90.0
npm ci --prefix worker
npm run format:check --prefix worker
npm run lint --prefix worker
npm run check --prefix worker
npm test --prefix worker
npm run build --prefix worker
node --test scripts/*.test.js

Open questions

  1. Should the initial provider support only Replicate deployments, or both deployments and direct version predictions?
  2. What exact runner model schema should Crabbox standardize for archive, command, environment, logs, exit code, and artifacts?
  3. What maximum data URL archive size is acceptable for the first implementation?
  4. Is a Crabbox-controlled temporary object store acceptable for larger workspaces, or should large-workspace support be deferred?
  5. Should warmup create a lightweight health prediction, or should it only validate configuration to avoid unnecessary GPU billing?
  6. How should Crabbox tag/filter Replicate predictions so list and status avoid unrelated account predictions?

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal priority bug or improvement with limited blast radius.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.issue-rating: 🌊 off-meta tidepoolIssue quality rating does not apply to this item.

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions