command-executor
from front-depiction/claude-setup
Reusable Claude Code configuration for Effect TypeScript projects with specialized agents and skills
10 stars4 forksUpdated Jan 19, 2026
npx skills add https://github.com/front-depiction/claude-setup --skill command-executorSKILL.md
Command Execution with @effect/platform
Overview
The Command module provides type-safe, testable process execution with automatic resource cleanup. Use this for spawning child processes, running shell commands, capturing output, and managing process lifecycles.
When to use this skill:
- Running shell commands or external programs
- Spawning child processes with controlled stdio
- Capturing command output (string, lines, stream)
- Managing long-running processes with cleanup
- Setting environment variables or working directories
- Piping commands together
Note: This skill covers the Command module for process execution, NOT @effect/cli for building CLI applications.
Import Pattern
import { Command, CommandExecutor } from "@effect/platform"
Creating Commands
Basic Command
import { Command } from "@effect/platform"
import { pipe } from "effect"
declare const PROJECT_ROOT: string
// Simple command with arguments
const command = Command.make("echo", "-n", "test")
// With working directory
const commandWithDir = pipe(
Command.make("npm", "install"),
Command.workingDirectory("/path/to/project")
)
// With environment variables
const commandWithEnv = pipe(
Command.make("node", "script.js"),
Command.env({ NODE_ENV: "production", API_KEY: "xyz" })
)
// Control stdio streams
const commandWithStdio = pipe(
Command.make("hardhat", "node"),
Command.stdout("inherit"), // "inherit" | "pipe"
Command.stderr("inherit"),
Command.workingDirectory(PROJECT_ROOT)
)
Command Configuration Options
import { Command } from "@effect/platform"
import type { Stream } from "effect"
declare const stream: Stream.Stream<Uint8Array>
declare const stringInput: string
// stdout/stderr modes:
// - "inherit": Pass through to parent process
// - "pipe": Capture for programmatic access
const configuredCommand = pipe(
Command.make("some-command"),
Command.stdout("pipe"), // Capture output
Command.stderr("inherit"), // Show errors in console
Command.stdin(stream), // Pipe stream as stdin
Command.feed(stringInput) // Feed string as stdin
)
Executing Commands
Capture as String
import { Command } from "@effect/platform"
import { Effect } from "effect"
const result = Effect.gen(function* () {
const command = Command.make("echo", "-n", "hello")
const output = yield* Command.string(command)
// output: "hello"
return output
})
Capture as Lines
import { Command } from "@effect/platform"
import { Effect } from "effect"
const result = Effect.gen(function* () {
const command = Command.make("ls", "-1")
const lines = yield* Command.lines(command)
// lines: string[]
return lines
})
Stream Output
import { Command } from "@effect/platform"
import { Effect, Stream, Chunk, Console, pipe } from "effect"
declare const decoder: TextDecoder
const result = Effect.gen(function* () {
const command = Command.make("tail", "-f", "app.log")
// As line stream
const lineStream = Command.streamLines(command)
yield* Stream.runForEach(lineStream, (line) => Console.log(line))
// As byte stream
const byteStream = Command.stream(command)
yield* pipe(
byteStream,
Stream.mapChunks(Chunk.map((bytes) => decoder.decode(bytes))),
Stream.runCollect
)
})
Get Exit Code
import { Command } from "@effect/platform"
import { Effect } from "effect"
const result = Effect.gen(function* () {
const command = Command.make("test", "-f", "file.txt")
const exitCode = yield* Command.exitCode(command)
// exitCode: number (0 = success, non-zero = failure)
return exitCode
})
Process Management
Start Process with Handle
import { Command, CommandExecutor } from "@effect/platform"
import { Effect, Stream, pipe } from "effect"
declare const PROJECT_ROOT: string
declare function handleOutput(chunk: Uint8Array): Effect.Effect<void>
const program = Effect.gen(function* () {
// Get the executor service
const executor = yield* CommandExecutor.CommandExecutor
const command = pipe(
Command.make("bunx", "hardhat", "node"),
Command.workingDirectory(PROJECT_ROOT),
Command.stdout("inherit"),
Command.stderr("inherit")
)
// Start returns a process handle
const process = yield* executor.start(command)
// Check if running
const isRunning = yield* process.isRunning
// Kill the process
yield* process.kill("SIGTERM") // or "SIGKILL", "SIGINT", etc.
// Access streams (when stdout/stderr are "pipe")
yield* Stream.runForEach(process.stdout, handleOutput)
})
Automatic Cleanup with Finalizers
import { Command, CommandExecutor } from "@effect/platform"
import { Effect, pipe } from "effect"
declare const PROJECT_ROOT: string
declare const waitForHardhat: Effect.Effect<void>
const startHardhatNode = Effect.gen(function* () {
const executor = yield* Com
...
Repository Stats
Stars10
Forks4