Skip to Content
DocumentationRegistryFeaturesRemote Client Module

@loopstack/remote-client

Remote environment module for the Loopstack  automation framework.

HTTP client and workflow tools for communicating with a Loopstack remote server — the sandboxed process that owns a workspace’s filesystem and shell. This module provides the foundation that other feature modules (git, code-agent, file-explorer) build on top of.

When to Use

  • You need to read, write, or edit files on a remote workspace from within a workflow
  • You need to execute shell commands on a remote instance
  • You need to manage application lifecycle (rebuild, reset, logs) on a remote environment
  • You are building a module that needs low-level access to the remote server API — inject RemoteClient directly

Installation

npm install @loopstack/remote-client

Register the module with forRoot():

import { RemoteClientModule } from '@loopstack/remote-client'; @Module({ imports: [RemoteClientModule.forRoot()], }) export class AppModule {}

RemoteClientModule.forRoot() registers globally and depends on SecretsModule and TypeORM entities (WorkspaceEntity, WorkspaceEnvironmentEntity).

Quick Start

Inject tools directly into your workflow via the constructor — they are NestJS providers resolved by their @Tool({ name }) value through DI:

import { BaseWorkflow, Transition, Workflow } from '@loopstack/common'; import { BashTool, EditTool, ReadTool } from '@loopstack/remote-client'; @Workflow({ uiConfig: __dirname + '/my.ui.yaml' }) export class MyWorkflow extends BaseWorkflow { constructor( private readonly read: ReadTool, private readonly edit: EditTool, private readonly bash: BashTool, ) { super(); } @Transition({ from: 'ready', to: 'done' }) async bumpVersion(state: unknown, ctx: RunContext): Promise<void> { const { data } = await this.read.call({ file_path: 'package.json' }); await this.edit.call({ file_path: 'package.json', old_string: '"version": "0.1.0"', new_string: '"version": "0.2.0"', }); await this.bash.call({ command: 'npm install' }); } }

Every tool automatically resolves the remote agent URL from the current execution scope — you never pass connection details manually.

How It Works

A Loopstack workspace runs inside a remote server (container, VM, or local process) that exposes an HTTP API for file operations, shell commands, and environment management.

Workflow / Tool | v EnvironmentService --> resolves agent URL from execution scope | v RemoteClient --> typed HTTP client (fetch-based) | v Remote Server --> /files/*, /exec, /app/*, /git/*

EnvironmentService resolves the correct remote agent URL for the current workflow execution. It caches environments per execution scope and prefers the sandbox slot by default.

RemoteClient is a plain @Injectable() service that wraps all HTTP calls to the remote server. It handles file operations, shell execution, app lifecycle, and git operations. You can inject it directly for advanced use cases.

Using RemoteClient directly

For cases where tools are not sufficient, inject RemoteClient and EnvironmentService:

import { Injectable } from '@nestjs/common'; import { EnvironmentService, RemoteClient } from '@loopstack/remote-client'; @Injectable() export class MyService { constructor( private readonly client: RemoteClient, private readonly env: EnvironmentService, ) {} async listFiles(path: string): Promise<string[]> { const url = await this.env.getAgentUrl(); const result = await this.client.glob(url, `${path}/**/*`); return result.files; } }

forFeature() — Registering environment slots

Use RemoteClientModule.forFeature() to register environment slot configurations from other modules:

RemoteClientModule.forFeature({ slots: [{ id: 'sandbox', label: 'Sandbox', type: 'fly' }], });

Tools Reference

All tools resolve the remote agent URL automatically from the execution scope.

File Operations

read

Reads a file from a remote instance. Returns file content. Supports offset and limit for reading specific line ranges.

ArgTypeRequiredDescription
file_pathstringYesThe file path to read
offsetnumberNoLine number to start reading from (1-indexed)
limitnumberNoNumber of lines to read

Returns: { content: string, path: string }

write

Writes a file to a remote instance. Creates parent directories if needed. Overwrites existing files.

ArgTypeRequiredDescription
file_pathstringYesThe file path to write
contentstringYesThe content to write to the file

Returns: { success: boolean, path: string }

edit

Performs exact string replacement in a file on a remote instance. Fails if old_string is not unique unless replace_all is true.

ArgTypeRequiredDescription
file_pathstringYesThe file path to edit
old_stringstringYesThe exact string to find and replace
new_stringstringYesThe replacement string
replace_allbooleanNoReplace all occurrences (default: false)

Returns: { success: boolean, path: string, replacements: number }

glob

Finds files by glob pattern on a remote instance. Returns relative file paths.

ArgTypeRequiredDescription
patternstringYesGlob pattern to match files (e.g. **/*.ts)
pathstringNoDirectory to search in, relative to workspace root

Returns: { files: string[] }

grep

Searches file contents by regex pattern on a remote instance. Returns matching lines with file paths and line numbers.

ArgTypeRequiredDescription
patternstringYesRegex pattern to search for in file contents
pathstringNoDirectory to search in, relative to workspace root
globstringNoGlob pattern to filter files (e.g. *.ts)
typestringNoFile type filter (e.g. js, ts, py)
case_insensitivebooleanNoCase-insensitive search

Returns: { matches: { file: string, line: number, content: string }[] }

Shell

bash

Executes a shell command on a remote instance. Returns stdout, stderr, and exit code.

ArgTypeRequiredDescription
commandstringYesThe shell command to execute
timeoutnumberNoTimeout in milliseconds

Returns: { stdout: string, stderr: string, exitCode: number }

App Lifecycle

rebuild_app

Rebuilds and restarts the app on a remote instance. Takes no arguments.

Returns: { success: boolean, message: string }

reset_workspace

Resets the workspace to its initial state, clearing all changes, temp files, database, and Redis. Takes no arguments.

Returns: { success: boolean, message: string }

logs

Retrieves application logs from the remote instance. Returns stdout and/or stderr output from the running application.

ArgTypeRequiredDescription
linesnumberNoNumber of recent log lines to return (default 100, max 5000)
type"out" | "error" | "all"NoWhich logs to retrieve (default "all")

Returns: { stdout: string, stderr: string }

Secrets

sync_secrets

Syncs all workspace secrets to the remote environment as .env variables and restarts the app. Call this before or during app restart to ensure secrets (API keys, config values) are available.

Takes no arguments.

Returns: { success: boolean, count: number } or { success: true, count: 0, message: string } when no secrets exist.

Configuration

forRoot() options

RemoteClientModule.forRoot({ environments: { available: [{ type: 'fly', label: 'Fly.io Machine' }], }, });
OptionTypeDescription
environments.availableAvailableEnvironmentInterface[]List of available environment types users can provision

Public API

  • Module: RemoteClientModule
  • Services: RemoteClient, EnvironmentService, EnvironmentConfigService
  • Controller: EnvironmentController
  • Tools: ReadTool, WriteTool, EditTool, BashTool, GlobTool, GrepTool, RebuildAppTool, ResetWorkspaceTool, LogsTool, SyncSecretsTool
  • Entities: WorkspaceEnvironmentEntity
  • DTOs: WorkspaceEnvironmentContextDto, WorkspaceEnvironmentDto
  • Types: RemoteClientModuleOptions, RemoteClientFeatureOptions, BashArgs, BashResult, EditArgs, EditResult, GlobArgs, GlobResult, GrepArgs, GrepResult, LogsArgs, LogsResult, ReadArgs, ReadResult, RebuildAppResult, ResetWorkspaceResult, SyncSecretsResult, WriteArgs, WriteResult, FileReadResponse, FileEditResponse, ExecResponse, GlobResponse, GrepMatch, GrepResponse

Dependencies

  • @loopstack/common — framework utilities, BaseTool, @Tool, @Transition, EXECUTION_SCOPE
  • @loopstack/secrets-module — consumed by SyncSecretsTool to read workspace secrets
  • @nestjs/common, @nestjs/core — NestJS framework and DiscoveryModule
  • @nestjs/typeorm, typeorm — workspace and environment entity persistence
  • zod — tool argument schema validation

About

Author: Jakob Klippel 

License: MIT

Last updated on